• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-159  評論-223  文章-30  trackbacks-0
               ICMP在IP系統間傳遞差錯和管理報文,是任何IP系統必須實現的組成部分。Linux 2.6.34中ICMP模塊的實現在linux/icmp.h,net/icmp.h和ipv4/icmp.c中,導出了icmp_err_convert數組和icmp_send函數,供其它網絡子系統使用。在其它網絡子系統中,當檢測到錯誤時,調用icmp_send產生并發送相應的ICMP差錯消息到源主機;當源主機收到ICMP不可達差錯消息,傳遞到原始套接字和傳輸層,而它們使用icmp_err_convert把對應的消息代碼轉換成套接字層比較容易理解的錯誤代碼。在內核空間中可發送的ICMP消息包括查詢應答和差錯報文,下面總結了產生這兩類消息的網絡子系統(及函數)與錯誤轉換。


            應答消息
               應答消息由ICMP模塊的內部函數icmp_reply而非icmp_send發送。根據RFC1122 3.2.2.9規范, 除非一個主機作為地址掩碼代理,否則不能發送回復,這對應ICMP的icmp_address實現為空,因此上表沒有列出地址掩碼應答項(內核符號為ICMP_ADDRESSREPLY)。

            差錯消息
               差錯消息由中間路由器或目的主機產生,當數據報不能成功提交給目的主機時。從上表可見,在IP層的接收、本地處理、轉發和輸出各過程中,都可能產生差錯消息;在傳輸層如果對應的端口沒有打開,那么UDP會產生ICMP端口不可達差錯,而TCP則會使用自己的差錯處理機制發送一個RST復位包,這也是上表沒有列出TCP子系統的原因。對于重定向差錯,由ICMP模塊的icmp_redirect調用ip_rt_redirect更新路由;其它差錯則由icmp_unreach處理。


            錯誤轉換
               第2列為icmp_err_convert數組索引,第4列也就是調用socket API出錯時返回的errno,最后1列為icmp_err_convert中的fatal成員取值,0表示非致命錯誤,1表示致命錯誤,需要報告給用戶進程。錯誤轉換會被RAW的raw_err、TCP的tcp_v4_err和UDP的udp_err用到,對于ICMP_DEST_UNREACH類型的差錯,使用上表轉換;ICMP_SOURCE_QUENCH類型的忽略不處理;ICMP_PARAMETERPROB類型的轉換成EPROTO(協議錯誤);ICMP_TIME_EXCEEDED類型的轉換成EHOSTUNREACH
               在這要注意,從ICMP_PORT_UNREACH到ECONNREFUSED的轉換,不適用于TCP,原因已在上節說明;而對于UDP的未連接套接字,如果主機在線而端口沒打開,調用sendto得不到ECONNREFUSED錯誤,但recvfrom會阻塞,這是因為雖然內核收到了ICMP差錯,但沒上報給應用進程。盡管如此,如果想得到ECONNREFUSED錯誤,那么可以寫個ICMP守護進程,應用進程先把它的套接字描述符通過unix域套接口傳遞到ICMP守護進程,而守護進程使用raw socket來接收ICMP差錯,再發給應用進程。


            發送限速
               不論一般差錯消息還是重定向差錯消息,發送限速針對的都是特定目標主機。
               一般限速
               在使用icmp_send發送差錯消息(PMTU消息除外)時,為減少網絡擁塞而限制了發送的速率,限速由xrlim_allow函數實現,定義在ipv4/icmp.c中。
             1#define XRLIM_BURST_FACTOR 6
             2int xrlim_allow(struct dst_entry *dst, int timeout)
             3{
             4    unsigned long now, token = dst->rate_tokens;
             5    int rc = 0;
             6
             7    now = jiffies;
             8    token += now - dst->rate_last;
             9    dst->rate_last = now;
            10    if (token > XRLIM_BURST_FACTOR * timeout)
            11        token = XRLIM_BURST_FACTOR * timeout;
            12    if (token >= timeout) {
            13        token -= timeout;
            14        rc = 1;
            15    }

            16    dst->rate_tokens = token;
            17    return rc;
            18}
               dst為目標路由緩存,timeout為允許發送的超時(單位為jiffies),dst->rate_tokens記錄令牌的個數,當令牌個數不小于timeout時,則減少timeout并允許發送一個消息;反之則不能發送,需等到令牌個數累積到大于timeout時才能發送,但是不能無限大,否則就會導致在一個可能很短的timeout內,發送遠多于6個的消息,引起ICMP風暴,所以這里限制了令牌的最大值為XRLIM_BURST_FACTOR*timeout即6倍的超時,也就是說在一個timeout內,最多能發送6個差錯消息。 
              
               重定向限速
               路由子系統使用ip_rt_send_redirect來發送重定向消息,定義在ipv4/route.c中,該函數內部調用icmp_send實現,在它的限速基礎上,使用指數回退算法控制發送速率。
             1void ip_rt_send_redirect(struct sk_buff *skb)
             2{
             3    struct rtable *rt = skb_rtable(skb);
             4    
               
             5
             6    /* No redirected packets during ip_rt_redirect_silence;
             7     * reset the algorithm.
             8     */

             9    if (time_after(jiffies, rt->u.dst.rate_last + ip_rt_redirect_silence))
            10        rt->u.dst.rate_tokens = 0;
            11
            12    /* Too many ignored redirects; do not send anything
            13     * set u.dst.rate_last to the last seen redirected packet.
            14     */

            15    if (rt->u.dst.rate_tokens >= ip_rt_redirect_number{
            16        rt->u.dst.rate_last = jiffies;
            17        return;
            18    }

            19
            20    /* Check for load limit; set rate_last to the latest sent
            21     * redirect.
            22     */

            23    if (rt->u.dst.rate_tokens == 0 || time_after(jiffies, (rt->u.dst.rate_last (ip_rt_redirect_load << rt->u.dst.rate_tokens)))) {
            24        icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
            25        rt->u.dst.rate_last = jiffies;
            26        ++rt->u.dst.rate_tokens;
            27        
            28    }

            29}
               重定向差錯使用ip_rt_redirect_silence(默認為(HZ/50)<<10)、ip_rt_redirect_number(默認為9)和ip_rt_redirect_load(默認為HZ/50)3個量來控制發送的速率;rt->u.dst.rate_last記錄上次發送的時間,rt->u.dst.rate_tokens累計發送總數,最大值為ip_rt_redirect_number;當兩次發送的時間間隔超過ip_rt_redirect_silence或ip_rt_redirect_load<<rt->u.dst.rate_tokens,并且發送總數不超過ip_rt_redirect_number時,才允許發送一個,這樣一來,在ip_rt_redirect_silence間隔內,每次發送的超時呈2的指數增長,達到了變減速發送的效果,直到總數達到ip_rt_redirect_number時停止發送,這是因為源主機可能忽略了重定向消息所以停止發送;當ip_rt_redirect_silence時間過后,又允許發送了,這是因為認為源主機沒有更新路由所以又需要發送。
            posted on 2015-05-18 19:52 春秋十二月 閱讀(2796) 評論(0)  編輯 收藏 引用 所屬分類: Network
            亚洲一区二区三区日本久久九| 欧美熟妇另类久久久久久不卡| 伊人久久大香线蕉影院95| 人人狠狠综合久久亚洲88| 久久91这里精品国产2020| 国内精品伊人久久久久妇| 精品国产乱码久久久久久郑州公司| 精品久久一区二区| 免费精品久久久久久中文字幕| 一本色道久久88精品综合| 久久久久久久99精品免费观看| 日本精品一区二区久久久| 久久久久亚洲AV成人片| 人人狠狠综合久久亚洲高清| 久久久精品2019免费观看| 国产精品内射久久久久欢欢 | 噜噜噜色噜噜噜久久| 99热成人精品热久久669| 久久久黄色大片| 精品久久久久久无码免费| 久久青青草原亚洲av无码app| 久久人人爽人人爽AV片| 久久精品国产亚洲一区二区| 中文精品久久久久人妻不卡| 免费一级欧美大片久久网| 麻豆精品久久精品色综合| 日韩人妻无码精品久久免费一| 久久天天躁狠狠躁夜夜av浪潮| 久久精品国内一区二区三区| 久久99国产精品尤物| 日本欧美久久久久免费播放网| 国产精品久久久久久久久软件| 久久久久成人精品无码| 久久婷婷综合中文字幕| 久久精品国产亚洲网站| 久久99精品国产自在现线小黄鸭 | 成人亚洲欧美久久久久| 久久国产精品99精品国产987| 久久精品国产亚洲AV高清热| 久久影院综合精品| 国内精品久久九九国产精品|