2012年12月14日 星期五

/proc/sys/net/core/優化

該目錄下的配置文件主要用來控制內核和網絡層之間的交互行為。
1) /proc/sys/net/core/message_burst
寫新的警告消息所需的時間(以 1/10 秒為單位);在這個時間內系統接收到的其它警告消息會被丟棄。這用于防止某些企圖用消息“淹沒”系統的人所使用的拒絕服務(Denial of Service)攻擊。
缺省設置:50(5秒)
2) /proc/sys/net/core/message_cost
該文件表示寫每個警告消息相關的成本值。該值越大,越有可能忽略警告消息。
缺省設置:5
3) /proc/sys/net/core/netdev_max_backlog
該文件表示在每個網絡接口接收數据包的速率比內核處理這些包的速率快時,允許送到隊列的數据包的最大數目。
缺省設置:300
4) /proc/sys/net/core/optmem_max
該文件表示每個套接字所允許的最大緩沖區的大小。
缺省設置:10240
5) /proc/sys/net/core/rmem_default
該文件指定了接收套接字緩沖區大小的缺省值(以字節為單位)。
缺省設置:110592
6) /proc/sys/net/core/rmem_max
該文件指定了接收套接字緩沖區大小的最大值(以字節為單位)。
缺省設置:131071
7) /proc/sys/net/core/wmem_default
該文件指定了發送套接字緩沖區大小的缺省值(以字節為單位)。
缺省設置:110592
8) /proc/sys/net/core/wmem_max
該文件指定了發送套接字緩沖區大小的最大值(以字節為單位)。
缺省設置:131071
9) 待續。。。
六、/proc/sys/net/ipv4/優化
1)     /proc/sys/net/ipv4/ip_forward
該文件表示是否打開IP轉發。
0,禁止
1,轉發
缺省設置:0
2)     /proc/sys/net/ipv4/ip_default_ttl
該文件表示一個數据報的生存周期(Time To Live),即最多經過多少路由器。
缺省設置:64
增加該值會降低系統性能。
3)     /proc/sys/net/ipv4/ip_no_pmtu_disc
該文件表示在全局范圍內關閉路徑MTU探測功能。
缺省設置:0
4)     /proc/sys/net/ipv4/route/min_pmtu
該文件表示最小路徑MTU的大小。
缺省設置:552
5)     /proc/sys/net/ipv4/route/mtu_expires
該文件表示PMTU信息緩存多長時間(秒)。
缺省設置:600(秒)
6)     /proc/sys/net/ipv4/route/min_adv_mss
該文件表示最小的MSS(Maximum Segment Size)大小,取決于第一跳的路由器MTU。
缺省設置:256(bytes)
6.1 IP Fragmentation
1)     /proc/sys/net/ipv4/ipfrag_low_thresh/proc/sys/net/ipv4/ipfrag_low_thresh
兩個文件分別表示用于重組IP分段的內存分配最低值和最高值,一旦達到最高內存分配值,其它分段將被丟棄,直到達到最低內存分配值。
缺省設置:196608(ipfrag_low_thresh)
262144(ipfrag_high_thresh)
2)     /proc/sys/net/ipv4/ipfrag_time
該文件表示一個IP分段在內存中保留多少秒。
缺省設置:30(秒)
6.2 INET Peer Storage
1)     /proc/sys/net/ipv4/inet_peer_threshold
INET對端存儲器某個合適值,當超過該閥值條目將被丟棄。該閥值同樣決定生存
時間以及廢物收集通過的時間間隔。條目越多,存活期越低,GC 間隔越短。
缺省設置:65664
2)     /proc/sys/net/ipv4/inet_peer_minttl
條目的最低存活期。在重組端必須要有足夠的碎片(fragment)存活期。這個最低
存活期必須保証緩沖池容積是否少于 inet_peer_threshold。該值以 jiffies為
單位測量。
缺省設置:120
3)     /proc/sys/net/ipv4/inet_peer_maxttl
條目的最大存活期。在此期限到達之后,如果緩沖池沒有耗盡壓力的話(例如:緩
沖池中的條目數目非常少),不使用的條目將會超時。該值以 jiffies為單位測量。
缺省設置:600
4)     /proc/sys/net/ipv4/inet_peer_gc_mintime
廢物收集(GC)通過的最短間隔。這個間隔會影響到緩沖池中內存的高壓力。 該值
以 jiffies為單位測量。
缺省設置:10
2006-10-31 16:33 清水飄萍
5)     /proc/sys/net/ipv4/inet_peer_gc_maxtime
廢物收集(GC)通過的最大間隔,這個間隔會影響到緩沖池中內存的低壓力。 該值
以 jiffies為單位測量。
缺省設置:120
6.3 TCP Variables
1)     /proc/sys/net/ipv4/tcp_syn_retries
該文件表示本机向外發起TCP SYN連接超時重傳的次數,不應該高于255;該值僅僅針對外出的連接,對于進來的連接由tcp_retries1控制。
缺省設置:5
2)     /proc/sys/net/ipv4/tcp_keepalive_probes
該文件表示丟棄TCP連接前,進行最大TCP保持連接偵測的次數。保持連接僅在
SO_KEEPALIVE套接字選項被打開時才被發送。
缺省設置:9(次)
3)     /proc/sys/net/ipv4/tcp_keepalive_time
該文件表示從不再傳送數据到向連接上發送保持連接信號之間所需的秒數。
缺省設置:7200(2小時)
4)     /proc/sys/net/ipv4/tcp_keepalive_intvl
該文件表示發送TCP探測的頻率,乘以tcp_keepalive_probes表示斷開沒有相應的TCP連接的時間。
缺省設置:75(秒)
5)     /proc/sys/net/ipv4/tcp_retries1
該文件表示放棄回應一個TCP連接請求前進行重傳的次數。

缺省設置:3
6)     /proc/sys/net/ipv4/tcp_retries2
該文件表示放棄在已經建立通訊狀態下的一個TCP數据包前進行重傳的次數。

缺省設置:15
7)     /proc/sys/net/ipv4/tcp_orphan_retries
在近端丟棄TCP連接之前,要進行多少次重試。默認值是 7 個,相當于 50秒–
16分鐘,視 RTO 而定。如果您的系統是負載很大的web服務器,那麼也許需
要降低該值,這類 sockets 可能會耗費大量的資源。另外參考
tcp_max_orphans。
8)     /proc/sys/net/ipv4/tcp_fin_timeout
對于本端斷開的socket連接,TCP保持在FIN-WAIT-2狀態的時間。對方可能
會斷開連接或一直不結束連接或不可預料的進程死亡。默認值為 60 秒。過去在
2.2版本的內核中是 180 秒。您可以設置該值,但需要注意,如果您的机器為負
載很重的web服務器,您可能要冒內存被大量無效數据報填滿的風險,
FIN-WAIT-2 sockets 的危險性低于 FIN-WAIT-1,因為它們最多只吃 1.5K
的內存,但是它們存在時間更長。另外參考 tcp_max_orphans。
缺省設置:60(秒)
9)     /proc/sys/net/ipv4/tcp_max_tw_buckets
系統在同時所處理的最大timewait sockets 數目。如果超過此數的話,
time-wait socket 會被立即砍除並且顯示警告信息。之所以要設定這個限制,純
粹為了抵御那些簡單的 DoS 攻擊,千萬不要人為的降低這個限制,不過,如果
網絡條件需要比默認值更多,則可以提高它(或許還要增加內存)。
缺省設置:180000
10) /proc/sys/net/ipv4/tcp_tw_recyle
打開快速 TIME-WAIT sockets 回收。除非得到技朮專家的建議或要求,請不要隨
意修改這個值。
缺省設置:0
11) /proc/sys/net/ipv4/tcp_tw_reuse
該文件表示是否允許重新應用處于TIME-WAIT狀態的socket用于新的TCP連接。
缺省設置:0
12) /proc/sys/net/ipv4/tcp_max_orphans
系統所能處理不屬于任何進程的TCP sockets最大數量。假如超過這個數量,那
麼不屬于任何進程的連接會被立即reset,並同時顯示警告信息。之所以要設定這
個限制,純粹為了抵御那些簡單的 DoS 攻擊,千萬不要依賴這個或是人為的降
低這個限制。
缺省設置:8192
13) /proc/sys/net/ipv4/tcp_abort_on_overflow
當守護進程太忙而不能接受新的連接,就向對方發送reset消息,默認值是false。
這意味著當溢出的原因是因為一個偶然的猝發,那麼連接將恢復狀態。只有在你确
信守護進程真的不能完成連接請求時才打開該選項,該選項會影響客戶的使用。
缺省設置:0
14) /proc/sys/net/ipv4/tcp_syncookies
該文件表示是否打開TCP同步標簽(syncookie),內核必須打開了 CONFIG_SYN_COOKIES項進行編譯。 同步標簽(syncookie)可以防止一個套接字在有過多試圖連接到達時引起過載。
缺省設置:0
15) /proc/sys/net/ipv4/tcp_stdurg
使用 TCP urg pointer 字段中的主机請求解釋功能。大部份的主机都使用老舊的
BSD解釋,因此如果您在 Linux 打開它,或會導致不能和它們正确溝通。
缺省設置:0
16) /proc/sys/net/ipv4/tcp_max_syn_backlog
對于那些依然還未獲得客戶端确認的連接請求,需要保存在隊列中最大數目。對于
超過 128Mb 內存的系統,默認值是 1024,低于 128Mb 的則為 128。如果
服務器經常出現過載,可以嘗試增加這個數字。警告!假如您將此值設為大于
1024,最好修改 include/net/tcp.h 里面的 TCP_SYNQ_HSIZE,以保持
TCP_SYNQ_HSIZE*16 0)或者bytes-bytes/2^(-tcp_adv_win_scale)(如
果tcp_adv_win_scale 128Mb 32768-610000)則系統將忽略所有發送給自己
的ICMP ECHO請求或那些廣播地址的請求。
缺省設置:1024
17) /proc/sys/net/ipv4/tcp_window_scaling
該文件表示設置tcp/ip會話的滑動窗口大小是否可變。參數值為布爾值,為1時表示可變,為0時表示不可變。tcp/ip通常使用的窗口最大可達到 65535 字節,對于高速網絡,該值可能太小,這時候如果啟用了該功能,可以使tcp/ip滑動窗口大小增大數個數量級,從而提高數据傳輸的能力。
缺省設置:1
18) /proc/sys/net/ipv4/tcp_sack
該文件表示是否啟用有選擇的應答(Selective Acknowledgment),這可以通過有選擇地應答亂序接收到的報文來提高性能(這樣可以讓發送者只發送丟失的報文段);(對于廣域網通信來說)這個選項應該啟用,但是這會增加對 CPU 的占用。
缺省設置:1
19) /proc/sys/net/ipv4/tcp_timestamps
該文件表示是否啟用以一種比超時重發更精确的方法(請參閱 RFC 1323)來啟用對 RTT 的計算;為了實現更好的性能應該啟用這個選項。
缺省設置:1
20) /proc/sys/net/ipv4/tcp_fack
該文件表示是否打開FACK擁塞避免和快速重傳功能。
缺省設置:1
21) /proc/sys/net/ipv4/tcp_dsack
該文件表示是否允許TCP發送“兩個完全相同”的SACK。
缺省設置:1
22) /proc/sys/net/ipv4/tcp_ecn
該文件表示是否打開TCP的直接擁塞通告功能。
缺省設置:0
23) /proc/sys/net/ipv4/tcp_reordering
該文件表示TCP流中重排序的數据報最大數量。
缺省設置:3
24) /proc/sys/net/ipv4/tcp_retrans_collapse
該文件表示對于某些有bug的打印机是否提供針對其bug的兼容性。
缺省設置:1
25) /proc/sys/net/ipv4/tcp_wmem
該文件包含3個整數值,分別是:min,default,max
Min:為TCP socket預留用于發送緩沖的內存最小值。每個TCP socket都可以使用它。
Default:為TCP socket預留用于發送緩沖的內存數量,默認情況下該值會影響其它協議使用的net.core.wmem中default的 值,一般要低于net.core.wmem中default的值。
Max:為TCP socket預留用于發送緩沖的內存最大值。該值不會影響net.core.wmem_max,今天選擇參數SO_SNDBUF則不受該值影響。默認值為128K。
缺省設置:4096 16384 131072
26) /proc/sys/net/ipv4/tcp_rmem
該文件包含3個整數值,分別是:min,default,max
Min:為TCP socket預留用于接收緩沖的內存數量,即使在內存出現緊張情況下TCP socket都至少會有這麼多數量的內存用于接收緩沖。
Default:為TCP socket預留用于接收緩沖的內存數量,默認情況下該值影響其它協議使用的 net.core.wmem中default的值。該值決定了在tcp_adv_win_scale、tcp_app_win和tcp_app_win的 默認值情況下,TCP 窗口大小為65535。
Max:為TCP socket預留用于接收緩沖的內存最大值。該值不會影響 net.core.wmem中max的值,今天選擇參數 SO_SNDBUF則不受該值影響。
缺省設置:4096 87380 174760
27) /proc/sys/net/ipv4/tcp_mem
該文件包含3個整數值,分別是:low,pressure,high
Low:當TCP使用了低于該值的內存頁面數時,TCP不會考慮釋放內存。
Pressure:當TCP使用了超過該值的內存頁面數量時,TCP試圖穩定其內存使用,進入pressure模式,當內存消耗低于low值時則退出pressure狀態。
High:允許所有tcp sockets用于排隊緩沖數据報的頁面量。
一般情況下這些值是在系統啟動時根据系統內存數量計算得到的。
缺省設置:24576 32768 49152
28) /proc/sys/net/ipv4/tcp_app_win
該文件表示保留max(window/2^tcp_app_win, mss)數量的窗口由于應用緩沖。當為0時表示不需要緩沖。
缺省設置:31
29) /proc/sys/net/ipv4/tcp_adv_win_scale
該文件表示計算緩沖開銷bytes/2^tcp_adv_win_scale(如果tcp_adv_win_scale >; 0)或者bytes-bytes/2^(-tcp_adv_win_scale)(如果tcp_adv_win_scale <= 0)。
缺省設置:2
6.4 IP Variables
1)     /proc/sys/net/ipv4/ip_local_port_range
該文件表示TCP/UDP協議打開的本地端口號。
缺省設置:1024 4999
建議設置:32768 61000
2)     /proc/sys/net/ipv4/ip_nonlocal_bind
該文件表示是否允許進程邦定到非本地地址。
缺省設置:0
3)     /proc/sys/net/ipv4/ip_dynaddr
該參數通常用于使用撥號連接的情況,可以使系統動能夠立即改變ip包的源地址為該ip地址,同時中斷原有的tcp對話而用新地址重新發出一個syn請求 包,開始新的tcp對話。在使用ip欺騙時,該參數可以立即改變偽裝地址為新的ip地址。該文件表示是否允許動態地址,如果該值非0,表示允許;如果該值 大于1,內核將通過log記錄動態地址重寫信息。
缺省設置:0
4)     /proc/sys/net/ipv4/icmp_echo_ignore_all/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
該文件表示內核是否忽略所有的ICMP ECHO請求,或忽略廣播和多播請求。
0, 響應請求
1, 忽略請求
缺省設置:0
建議設置:1
5)     /proc/sys/net/ipv4/icmp_ratelimit
6)     /proc/sys/net/ipv4/icmp_ratemask
7)     /proc/sys/net/ipv4/icmp_ignore_bogus_error_reponses
某些路由器違背RFC1122標准,其對廣播幀發送偽造的響應來應答。這種違背行
為通常會被以告警的方式記錄在系統日志中。如果該選項設置為True,內核不會
記錄這種警告信息。
缺省設置:0
8)     /proc/sys/net/ipv4/igmp_max_memberships
該文件表示多播組中的最大成員數量。
缺省設置:20
6.5 Other Configuration
1)     /proc/sys/net/ipv4/conf/*/accept_redirects
如果主机所在的網段中有兩個路由器,你將其中一個設置成了缺省網關,但是該網關
在收到你的ip包時發現該ip包必須經過另外一個路由器,這時這個路由器就會給你
發一個所謂的“重定向”icmp包,告訴將ip包轉發到另外一個路由器。參數值為布爾
值,1表示接收這類重定向icmp 信息,0表示忽略。在充當路由器的linux主机上缺
省值為0,在一般的linux主机上缺省值為1。建議將其改為0以消除安全性隱患。
2)     /proc/sys/net/ipv4/*/accept_source_route
是否接受含有源路由信息的ip包。參數值為布爾值,1表示接受,0表示不接受。在
充當網關的linux主机上缺省值為1,在一般的linux主机上缺省值為0。從安全性角
度出發,建議關閉該功能。
3)     /proc/sys/net/ipv4/*/secure_redirects
其實所謂的“安全重定向”就是只接受來自網關的“重定向”icmp包。該參數就是
用來設置“安全重定向”功能的。參數值為布爾值,1表示啟用,0表示禁止,缺省值
為啟用。
4)     /proc/sys/net/ipv4/*/proxy_arp
設置是否對網絡上的arp包進行中繼。參數值為布爾值,1表示中繼,0表示忽略,
缺省值為0。該參數通常只對充當路由器的linux主机有用。

Linux Kernel Network Stack code 的準備知識

轉:http://blog.csdn.net/cz_hyf/archive/2006/02/19/602802.aspx

1. linux內核ipv4網絡部分分層結構

BSD socket層:這一部分處理BSD socket相關操作,每個socket在內核中以struct socket結構體現。這一部分的文件
主要有:/net/socket.c /net/protocols.c etc INET socket層: BSD socket是個可以用於各種網絡協議的接口,而當用於tcp/ip,即建立了AF_INET形式的socket時,

還需要保留些額外的參數,於是就有了struct sock結構。文件主要
有:/net/ipv4/protocol.c /net/ipv4/af_inet.c /net/core/sock.c etc TCP/UDP層:處理傳輸層的操作,傳輸層用struct inet_protocol和struct proto兩個結構表示。文件主要

有:/net/ipv4/udp.c /net/ipv4/datagram.c /net/ipv4/tcp.c /net/ipv4/tcp_input.c /net/ipv4//tcp_output.c /net/ipv4/tcp_minisocks. c /net/ipv4/tcp_output.c /net/ipv4/tcp_timer.c
etc  IP層:處理網絡層的操作,網絡層用struct packet_type結構表示。文件主要有:/net/ipv4/ip_forward.c
 
ip_fragment.c ip_input.c ip_output.c etc. 數據鏈路層和驅動程序:每個網絡設備以struct net_device表示,通用的處理在dev.c中,驅動程序都在/driver/net目

錄下。
2. 兩台主機建立udp通信所走過的函數列表
^
| sys_read fs/read_write.c
| sock_read net/socket.c
| sock_recvmsg net/socket.c
| inet_recvmsg net/ipv4/af_inet.c
| udp_recvmsg net/ipv4/udp.c
| skb_recv_datagram net/core/datagram.c
| -------------------------------------------
| sock_queue_rcv_skb include/net/sock .h
| udp_queue_rcv_skb net/ipv4/udp.c
| udp_rcv net/ipv4/udp.c
| ip_local_deliver_finish net/ipv4/ip_input.c
| ip_local_deliver net/ipv4/ip_input.c
| ip_recv net/ipv4/ip_input.c
| net_rx_action net /dev.c
| -------------------------------------------
| netif_rx net/dev.c
| el3_rx driver/net/3c309.c
| el3_interrupt driver/net/3c309.c 

========================== 
| sys_write fs/read_write.c 
| sock_writev net/socket.c                    
| sock_sendmsg net/socket.c 
| inet_sendmsg net/ipv4/af_inet.c 
| udp_sendmsg net/ipv4/udp.c
| ip_build_xmit net/ipv4/ip_output.c 
| output_maybe_reroute net /ipv4/ip_output.c 
| ip_output net/ipv4/ip_output.c
| ip_finish_output net/ipv4/ip_output.c 
| dev_queue_xmit net/dev.c 
| ------------------ -------------------------- 
| el3_start_xmit driver/net/3c309.c 

3. 網絡路徑圖、重要數據結構sk_buffer及路由介紹
    linux-net.pdf 第2.1章第2.3章第2.4章
    
4. 從連接、發送、到接收數據包的過程
    linux-net.pdf 第4、5、6章詳細闡述
二.linux的tcp-ip棧代碼的詳細分析
1.數據結構(msghdr,sk_buff,socket,sock,proto_ops,proto)
bsd套接字層,操作的對像是socket,數據存放在msghdr這樣的數據結構:
創建socket需要傳遞family,type,protocol三個參數,創建socket其實就是創建一個socket實例,然後創建一個文件描述符結構,並且互相建立一些關聯,即建立互相連接的指針,並且初始化這些對文件的寫讀操作映射到socket的read,write函數上來。
同時初始化socket的操作函數(proto_ops結構),如果傳入的type參數是STREAM類型,那麼就初始化為SOCKET->ops為inet_stream_ops,如果是DGRAM類型,則SOCKET-ops為inet_dgram_ops。對於inet_stream_ops其實是一個結構體,包含了stream類型的socket操作的一些入口函數,在這些函數里主要做的是對socket進行相關的操作,同時通過調用下面提到的sock中的相關操作完成socket到sock層的傳遞。比如在inet_stream_ops裡有個inet_release的操作,這個操作除了釋放socket的類型空間操作外,還通過調用socket連接的sock的close操作,對於stream類型來說,即tcp_close來關閉sock
釋放sock。
創建socket同時還創建sock數據空間,初始化sock,初始化過程主要做的事情是初始化三個隊列,receive_queue(接收到的數據包sk_buff鍊錶隊列),send_queue(需要發送數據包的sk_buff鍊錶隊列),backlog_queue(主要用於tcp中三次握手成功的那些數據包,自己猜的),根據family、type參數,初始化sock的操作,比如對於family為inet類型的,type為stream類型的,sock->proto初始化為tcp_prot.其中包括stream類型的協議sock操作對應的入口函數。
在一端對socket進行write的過程中,首先會把要write的字符串緩衝區整理成msghdr的數據結構形式(參見linux內核2.4版源代碼分析大全),然後調用sock_sendmsg把msghdr的數據傳送至inet層,對於msghdr結構中數據區中的每個數據包,創建sk_buff結構,填充數據,掛至發送隊列。一層層往下層協議傳遞。一下每層協議不再對數據進行拷貝。而是對sk_buff結構進行操作。
inet套接字及以下層數據存放在sk_buff這樣的數據結構裡:
路由:
    
    在linux的路由系統主要保存了三種與路由相關的數據,第一種是在物理上和本機相連接的主機地址信息表,第二種是保存了在網絡訪問中判斷一個網絡地址應該走什麼路由的數據表;第三種是最新使用過的查詢路由地址的緩存地址數據表。
    1.neighbour結構neighbour_table{ }是一個包含和本機所連接的所有鄰元素的信息的數據結構。該結構中有個元素是neighbour結構的數組,數組的每一個元素都是一個對應於鄰機的neighbour結構,系統中由於協議的不同,會有不同的判斷鄰居的方式,每種都有neighbour_table{ }類型的實例,這些實例是通過neighbour_table{}中的指針next串聯起來的。在neighbour結構中,包含有與該鄰居相連的網絡接口設備net_device的指針,網絡接口的硬件地址,鄰居的硬件地址,包含有neigh_ops{}指針,這些函數指針是直接用來連接傳輸數據的,包含有queue_xmit(struct * sk_buff)函數入口地址,這個函數可能會調用硬件驅動程序的發送函數。
    2.FIB結構在FIB中保存的是最重要的路由規則,通過對FIB數據的查找和換算,一定能夠獲得路由一個地址的方法。系統中路由一般採取的手段是:先到路由緩存中查找表項,如果能夠找到,直接對應的一項作為路由的規則;如果不能找到,那麼就到FIB中根據規則換算傳算出來,並且增加一項新的,在路由緩存中將項目添加進去。
    3.route結構(即路由緩存中的結構)
數據鏈路層:
  
   net_device{}結構,對應於每一個網絡接口設備。這個結構中包含很多可以直接獲取網卡信息的函數和變量,同時包含很多對於網卡操作的函數,這些直接指向該網卡驅動程序的許多函數入口,包括發送接收數據幀到緩衝區等。當這些完成後,比如數據接收到緩衝區後便由netif_rx(在net/core /dev.c各種設備驅動程序的上層框架程序)把它們組成sk_buff形式掛到系統接收的backlog隊列然後交由上層網絡協議處理。同樣,對於上層協議處理下來的那​​些sk_buff。便由dev_queue_xmit函數放入網絡緩衝區,交給網卡驅動程序的發送程序處理。
   在系統中存在一張鍊錶dev_base將系統中所有的net_device{}結構連在一起。對應於內核初始化而言,系統啟動時便為每個所有可能支持的網絡接口設備申請了一個net_device{}空間並串連起來,然後對每個接點運行檢測過程,如果檢測成功,則在dev_base鍊錶中保留這個接點,否則刪除。對應於模塊加載來說,則是調用register_netdev()註冊net_device,在這個函數中運行檢測過程,如果成功,則加到dev_base鍊錶。否則就返回檢測不到信息。刪除同理,調用
unregister_netdev。
2.啟動分析
    2.1初始化進程:start-kernel(main.c)---->do_basic_setup(main.c)---->sock_init(/net/socket.c)---->do_initcalls(main.c)
void __init sock_init(void) {
 int i;
 printk(KERN_INFO "Linux NET4.0 for Linux 2.4\n");
 printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n");
 /*
  * Initialize all address (protocol) families.每一項表示的是針對一個地址族的操作集合,例如對於ipv4來說,在net/ipv4/af_inet.c文件中的函數inet_proto_init()就調用sock_register( )函數將inet_families_ops初始化到屬於IPV4的net_families數組中的一項。
  */  for (i = 0; i < NPROTO; i++)   net_families[i] = NULL;
 /*
  * Initialize sock SLAB cache.初始化對於sock結構預留的內存的slab緩存。
  */  sk_init();
 
#ifdef SLAB_SKB
 /*
  * Initialize skbuff SLAB cache初始化對於skbuff結構的slab緩存。以後對於skbuff的申請可以通過函數kmem_cache_alloc()在這個緩存中申請空間。
  */
 skb_init();
#endif
 /*
  * Wan router layer.
  */
#ifdef CONFIG_WAN_ROUTER
 wanrouter_init();
#endif
 /*
  * Initialize the protocols module.向系統登記sock文件系統,並且將其安裝到系統上來。
  */
 register_filesystem(&sock_fs_type);
 sock_mnt = kern_mount(&sock_fs_type);
 /* The real protocol initialization is performed when
  * do_initcalls is run.
  */

 /*
  * The netlink device handler may be needed early.
  */
#ifdef CONFIG_NET
 rtnetlink_init();
#endif
#ifdef CONFIG_NETLINK_DEV
 init_netlink();
#endif
#ifdef CONFIG_NETFILTER
 netfilter_init();
#endif
#ifdef CONFIG_BLUEZ
 bluez_init();
#endif
/*yfhuang ipsec*/
#ifdef CONFIG_IPSEC         
 pfkey_init();
#endif
/*yfhuang ipsec*/
}
    2.2 do_initcalls()  中做了其它的初始化,其中包括
                協議初始化,路由初始化,網絡接口設備初始化
(例如inet_init函數以_init開頭表示是系統初始化時做,函數結束後跟module_init(inet_init),這是一個宏,在include/linux/init.c中定義,展開為_initcall(inet_init),表示這個函數在do_initcalls被調用了)
    2.3 協議初始化
此處主要列舉inet協議的初始化過程。
static int __init inet_init(void)
{
 struct sk_buff *dummy_skb;
 struct inet_protocol *p;
 struct inet_protosw *q;
 struct list_head *r;
 printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n");
 if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
  printk(KERN_CRIT "inet_proto_init: panic\n");
  return -EINVAL;
 }
 /*
  * Tell SOCKET that we are alive...註冊socket,告訴socket inet類型的地址族已經準備好了
  */    (void) sock_register(&inet_family_ops);
  
 /*
  * Add all the protocols.包括arp,ip、ICMP、UPD、tcp_v4、tcp、igmp的初始化,主要初始化各種協議對應的inode和socket變量。
其中arp_init完成系統中路由部分neighbour表的初始化
ip_init完成ip協議的初始化。在這兩個函數中,都通過定義一個packet_type結構的變量將這種數據包對應的協議發送數據、允許發送設備都做初始化。

  */
 printk(KERN_INFO "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;
 }
 /* Register the socket-side information for inet_create. */
 for(r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
  INIT_LIST_HEAD(r);
 for(q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
  inet_register_protosw(q);
 /*
  * Set the ARP module up
  */
 arp_init();
   /*
    * Set the IP module up
    */
 ip_init();
 tcp_v4_init(&inet_family_ops);
 /* Setup TCP slab cache for open requests. */
 tcp_init();

 /*
  * Set the ICMP layer up
  */
 icmp_init(&inet_family_ops);
 /* I wish inet_add_protocol had no constructor hook...
    I had to move IPIP from net/ipv4/protocol.c :-( --ANK
  */
#ifdef CONFIG_NET_IPIP
 ipip_init();
#endif
#ifdef CONFIG_NET_IPGRE
 ipgre_init();
# endif
 /*
  * Initialise the multicast router
  */
#if defined(CONFIG_IP_MROUTE)
 ip_mr_init();
#endif
 /*
  * Create all the /proc entries.
  */
#ifdef CONFIG_PROC_FS
 proc_net_create ("raw", 0, raw_get_info);
 proc_net_create ("netstat", 0, netstat_get_info);
 proc_net_create ("snmp", 0, snmp_get_info);
 proc_net_create ( "sockstat", 0, afinet_get_info);
 proc_net_create ("tcp", 0, tcp_get_info);
 proc_net_create ("udp", 0, udp_get_info);
#endif /* CONFIG_PROC_FS */
 ipfrag_init();
 return 0;
}   
module_init(inet_init);
                                                 
     2.4 路由初始化(包括neighbour表、FIB表、和路由緩存表的初始化工作)
            2.4.1 rtcache表ip_rt_init()函數在net/ipv4/ip_output中調用,net/ipv4/route.c中定義
            2.4.2 FIB初始化在ip_rt_init()中調用在net/ipv4/fib_front.c中定義
           2.4.3 neigbour表初始化arp_init()函數中定義 
     2.5 網絡接口設備初始化
             
             在系統中網絡接口都是由一個dev_base鍊錶進行管理的。通過內核的啟動方式也是通過這個鍊錶進行操作的。在系統啟動之初,將所有內核能夠支持的網絡接口都初始化成這個鍊錶中的一個節點,並且每個節點都需要初始化出init函數指針,用來檢測網絡接口設備。然後, 系統遍歷整個dev_base鍊錶,對每個節點分別調用init函數指針,如果成功,證明網絡接口設備可用,那麼這個節點就可以進一步初始化,如果返回失敗,那麼證明該網絡設備不存在或是不可用,只能將該節點刪除。啟動結束之後,在dev_base中剩下的都是可以用的網絡接口設備。
            2.5.1 do_initcalls---->net_dev_init()(net/core /dev.c)------>ethif_probe()(drivers/net/Space.c,在netdevice{}結構的init中調用,這邊ethif_probe是以太網卡針對的調用)
3.網絡設備驅動程序(略)
        
4.網絡連接
     4.1 連接的建立和關閉
            tcp連接建立的代碼如下:
                    server=gethostbyname(SERVER_NAME);
                    sockfd=socket(AF_INET,SOCK_STREAM,0);
                    address.sin_family=AF_INET;
                    address.sin_port=htons(PORT_NUM);
                    memcpy(&address.sin_addr,server->h_addr,server->h_length);
                    connect(sockfd,&address,sizeof(address));
       連接的初始化與建立期間主要發生的事情如下:
                      
       1)sys_socket調用:調用socket_creat(),創建出一個滿足傳入參數family、type、和protocol的socket,調用sock_map_fd()獲取一個未被使用的文件描述符,並且申請並初始化對應的file{ }結構。
        
       2)sock_creat():創建socket結構,針對每種不同的family的socket結構的初始化,就需要調用不同的create函數來完成。對應於inet類型的地址來說,在網絡協議初始化時調用sock_register()函數中完成註冊的定義如下:
        struct net_proto_family inet_family_ops={
                PF_INET;
                inet_create
        };所以inet協議最後會調用inet_create函數。
        
       3)inet_create: 初始化sock的狀態設置為SS_UNCONNECTED,申請一個新的sock結構,並且初始化socket的成員ops初始化為inet_stream_ops,而sock的成員prot初始化為tcp_prot。然後調用sock_init_data,將該socket結構的變量sock和sock類型的變量關聯起來。
       4)在系統初始化完畢後便是進行connect的工作,系統調用connect將一個和socket結構關聯的文件描述符和一個sockaddr{}結構的地址對應的遠程機器相關聯,並且調用各個協議自己對應的connect連接函數。對應於tcp類型,則sock->ops->connect便為inet_stream_connect。
       5)inet_stream_connect: 得到sk,sk=sock->sk,鎖定sk,對自動獲取sk的端口號存放在sk->num中,並且用htons()函數轉換存放在sk-& gt;sport中。然後調用sk->prot->connect()函數指針,對tcp協議來說就是tcp_v4_connect()函數。然後將sock->state狀態字設置為SS_CONNECTING,等待後面一系列的處理完成之後,就將狀態改成SS_CONNECTTED。
       6) tcp_v4_connect():調用函數ip_route_connect(),尋找合適的路由存放在rt中。ip_route_connect找兩次,第一次找到下一跳的ip地址,在路由緩存或fib中找到,然後第二次找到下一跳的具體鄰居,到neigh_table中找到。然後申請出tcp頭的空間存放在buff中。將sk中相關地址數據做一些針對路由的變動,並且初始化一個tcp連接的序列號,調用函數tcp_connect(),初始化tcp 頭,並設置tcp處理需要的定時器。一次connect()建立的過程就結束了。
       連接的關閉主要如下:
        1)close: 一個socket文件描述符對應的file{}結構中,有一個file_operations{}結構的成員f_ops,它的初始化關閉函數為sock_close函數。
        2)sock_close:調用函數sock_release(),參數為一個socket{}結構的指針。
        3)sock_release:調用inet_release,並釋放socket的指針和文件空間
        4)inet_release: 調用和該socket對應協議的關閉函數inet_release,如果是tcp協議,那麼調用的是tcp_close;最後釋放sk。
        4.2 數據發送流程圖
 
各層主要函數以及位置功能說明:
        1)sock_write:初始化msghdr{}結構net/socket.c
        2)sock_sendmsg:net/socket.c
        3)inet_sendmsg:net/ipv4/af_net.c
        4)tcp_sendmsg:申請sk_buff{}結構的空間,把msghdr{}結構中的數據填入sk_buff空間。net/ipv4/tcp.c
        5)tcp_send_skb:net/ipv4/tcp_output.c
        6)tcp_transmit_skb:net/ipv4/tcp_output.c
        7)ip_queue_xmit:net/ipv4/ip_output.c
        8)ip_queue_xmit2:net/ipv4/ip_output.c
        9)ip_output:net/ipv4/ip_output.c
        10)ip_finish_output:net/ipv4/ip_output.c
        11)ip_finish_output2:net/ipv4/ip_output.c
        12)neigh_resolve_output:net/core/neighbour.c
        13)dev_queue_xmit:net/core/dev.c
        4.3 數據接收流程圖
各層主要函數以及位置功能說明:
        1)sock_read:初始化msghdr{}的結構類型變量msg,並且將需要接收的數據存放的地址傳給msg.msg_iov->iov_base. net/socket.c
        2)sock_recvmsg: 調用函數指針sock->ops->recvmsg()完成在INET Socket層的數據接收過程.其中sock->ops被初始化為inet_stream_ops,其成員recvmsg對應的函數實現為inet_recvmsg()函數. net/socket.c
        3)sys_recv()/sys_recvfrom():分別對應著面向連接和麵向無連接的協議兩種情況. net/socket.c
        4)inet_recvmsg:調用sk->prot->recvmsg函數完成數據接收,這個函數對於tcp協議便是tcp_recvmsg net/ipv4/af_net.c
        5)tcp_recvmsg:從網絡協議棧接收數據的動作,自上而下的觸發動作一直到這個函數為止,出現了一次等待的過程.函數tcp_recvmsg可能會被動地等待在sk的接收數據隊列上,也就是說,系統中肯定有其他地方會去修改這個隊列使得tcp_recvmsg可以進行下去.入口參數sk是這個網絡連接對應的sock{}指針,msg用於存放接收到的數據.接收數據的時候會去遍歷接收隊列中的數據,找到序列號合適的.
        但讀取隊列為空時tcp_recvmsg就會調用tcp_v4_do_rcv使用backlog隊列填充接收隊列.
        6)tcp_v4_rcv:tcp_v4_rcv被ip_local_deliver函數調用,是從IP層協議向INET Socket層提交的"數據到"請求,入口參數skb存放接收到的數據,len是接收的數據的長度,這個函數首先移動skb- >data指針,讓它指向tcp頭,然後更新tcp層的​​一些數據統計,然後進行tcp的一些值的校驗.再從INET Socket層中已經建立的sock{}結構變量中查找正在等待當前到達數據的哪一項.可能這個sock{}結構已經建立,或者還處於監聽端口、等待數據連接的狀態。返回的sock結構指針存放在sk中。然後根據其他進程對sk的操作情況,將skb發送到合適的位置.調用如下:
        TCP包接收器(tcp_v4_rcv)將TCP包投遞到目的套接字進行接收處理. 當套接字正被用戶鎖定,TCP包將暫時排入該套接字的後備隊列(sk_add_backlog).這時如果某一用戶線程企圖鎖定該套接字(lock_sock),該線程被排入套接字的後備處理等待隊列(sk->lock.wq).當用戶釋放上鎖的套接字時(release_sock,在tcp_recvmsg中調用),後備隊列中的TCP包被立即註入TCP包處理器(tcp_v4_do_rcv)進行處理,然後喚醒等待隊列中最先的一個用戶來獲得其鎖定權. 如果套接字未被上鎖,當用戶正在讀取該套接字時, TCP包將被排入套接字的預備隊列(tcp_prequeue),將其傳遞到該用戶線程上下文中進行處理.如果添加到sk->prequeue不成功,便可以添加到sk->receive_queue隊列中(用戶線程可以登記到預備隊列,當預備隊列中出現第一個包時就喚醒等待線程.) /net/tcp_ipv4.c
        7)ip_rcv、ip_rcv_finish:從以太網接收數據,放到skb裡,作ip層的一些數據及選項檢查,調用ip_route_input()做路由處理,判斷是進行ip轉發還是將數據傳遞到高一層的協議.調用skb->dst->input函數指針,這個指針的實現可能有多種情況,如果路由得到的結果說明這個數據包應該轉發到其他主機,這裡的input便是ip_forward;如果數據包是給本機的,那麼input指針初始化為ip_local_deliver函數./net/ipv4/ip_input.c
        8)ip_local_deliver、ip_local_deliver_finish:入口參數skb存放需要傳送到上層協議的數據,從ip頭中獲取是否已經分拆的信息,如果已經分拆,則調用函數ip_defrag將數據包重組。然後通過調用ip_prot->handler指針調用tcp_v4_rcv(tcp)。ip_prot是inet_protocol結構指針,是用來ip層登記協議的,比如由udp,tcp,icmp等協議。/net/ipv4/ip_input.c

How to repair and clone disk with ddrescue

  ddrescue  is a tool that can be used to repair and clone disks on a  Linux system . This includes hard drives, partitions, DVD discs, flas...