Linux網橋實現分析-STP的實現分析_第1頁
Linux網橋實現分析-STP的實現分析_第2頁
Linux網橋實現分析-STP的實現分析_第3頁
Linux網橋實現分析-STP的實現分析_第4頁
Linux網橋實現分析-STP的實現分析_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、#1  Linux網橋實現分析-第三部份,STP的實現分析初步Linux網橋實現分析作者:kendo版權所有,轉載請注冊出處第三部份,STP的實現分析初步一、STP的框架結構STP發(fā)送的是wikiBPDU/wiki包,該包有所有兩種類型:配置和TCN(拓樸變更通知);對于BPDU包的處理,有兩種:接收和發(fā)送(廢話),對于配置類型的BPDU包的發(fā)送,它是靠定時器來完成的,參BPDU包的幾個定時器參數;對于wikiTCP/wiki類型的BPDU包的發(fā)送,從名字可以看出來,它是當發(fā)現拓樸結構發(fā)生變更時發(fā)送的,如本機網橋配置的變化,物理接口的變動,分析其它機器變動后發(fā)出來的STP包

2、等等。BPDU的封包采用的是IEEE802封包(本想把封包結構的圖片貼上來,找不著在哪兒上傳圖片)。前面分析過, br_handle_frame函數中,當網橋開啟了STP,且根據目的物理地址判斷出這是一個STP包,則交給br_stp_handle_bpdu函數處理。br_stp_handle_bpdu函數主要是判斷是哪種類型的BPDU包,然后調用相關的處理函數,即:if(type=config)    br_received_config_bpdu();else if(type=tcn)    br_received_tcn_bpdu();這是對接收到B

3、PDU包的處理,關于config類型的BPDU包的發(fā)送,后面再分析;TCN包的發(fā)送,有一部份是在接收包處理過程中處理的(因為分析config類型的BPDU包的時候,發(fā)現拓樸變更,當然要發(fā)送TCN包了),所以這里一起來分析。二、Config類型的BPDU包的接收處理這個處理過程是在拆完BPDU包后,調用br_received_config_bpdu函數完成的。還是得先交待一些理論的東西:STPwiki協議/wiki最終是為了在網絡中生成一棵無環(huán)狀的樹,以期消除廣播風暴以及單播數據幀對網絡的影響。它始終在選舉三樣東東:1、根網橋;2、根端口;3、“指定端口”和“指定網橋”(這三個概念非常重要,如果

4、你還不清楚,建議查閱相關文檔先,否則下邊的代碼分析也無從談起了)然后再根據選舉出來的這三個東東,確定端口的狀態(tài):阻塞、轉發(fā)、學習、監(jiān)聽、禁用要選舉出這三樣東東,得有一個判斷標志,即算法,STP的判斷標準是:1、判斷根橋ID,以最小的為優(yōu);2、判斷到根橋的最小路徑開銷;3、確定最小發(fā)送發(fā)BID(Sender BID)4、確定最小的端口ID如果前面你查閱了BPDU的封包結構,根橋ID、最小路徑開銷、發(fā)送方網橋的ID、端口ID這幾個概念應該沒有問題了,不過這里還是簡單交一下:1、根橋ID,我們配置了網橋后,用brctl命令會發(fā)現8000.XXXXXX這樣一串,這就是網橋的ID號,用一標識每一個網橋,

5、后面的XXXX一般的橋的MAC地址,這樣ID值就不會重復。根橋ID,是指網絡中所有網橋的ID值最小的那一個,對應的具有根橋ID的橋,當然也是網絡的根橋了;2、最小路徑開銷動態(tài)路由中也類似這個概念,不過這里用的不是跳數(局域網不比廣域網,不一定跳數大就慢,比如跳數小,是10M鏈路,跳數大的卻是千兆鏈路),最初的開銷定義為1000M/鏈種帶寬,當然,這種方式不適用于萬兆網了所以后來又有一個新的,對每一種鏈路定義一個常數值詳請請查閱相關資料;3、發(fā)送方ID網橋之前要收斂出一個無環(huán)狀拓樸,就需要互相發(fā)送BPDU包,當然需要把自己的ID告訴對方,這樣對方好拿來互相比較;4、端口ID端口ID由優(yōu)先級+端口

6、編號組成,用于標識某個橋的某個端口,后面比較時好用。生成樹算法就是利用上述四個參數在判斷,判斷過程總是相同的:1、確定根橋,橋ID最小的(即把包中的橋ID,同自己以前記錄的那個最小的橋ID相比,機器加電時,總是以自己的橋ID為根橋ID)的為根橋;2、確定最小路徑開銷;3、確定最小發(fā)送方ID;4、確定最小的端口ID:這四步非常地重要,后面的所以比較都是這四個步驟。有了這些概念,來看看對config類型的BPDU包的處理:void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) 

7、;       struct net_bridge *br;        int was_root;        if (p->state = BR_STATE_wikiDIS/wikiABLED)                return;        

8、br = p->br;        read_lock(&br->lock);        /*自己是根橋嗎?用自己的br_ID和BPDU包中的根ID相比較*/        was_root = br_is_root_bridge(br);                /

9、*比橋BPDU包中的信息(bpdu)和原先的對應的信息(p),如果需要更新,返回1,相同返回0,不需更新返回-1*/        if (br_supersedes_port_info(p, bpdu)                 /*刷新自己的相關信息*/                br_record_config_infor

10、mation(p, bpdu);                /*進行root_bridge、port的選舉*/                br_configuration_update(br);                /*設置端口狀態(tài)*/     

11、60;          br_port_state_selection(br);以上這一段的邏輯概念很簡單:1、把收到的BPDU包中的參數同自己原先記錄的相比較,(遵循前面說的四個比較步驟),以判斷是否需要進行更新br_supersedes_port_info(p, bpdu)。2、如果判斷需要進行更新,即上述四個步驟中,有任意一項有變動,則刷新自己的保存記錄:br_record_config_information(p, bpdu);3、因為有變動,就需要改變自己的配置了:br_configuration_update(br);即

12、前面說的,根據四步判斷后選舉根橋(注:根橋不是在這里選舉的,前文說過,它是定時器定時發(fā)送BPDU包,然后收到的機器只需改變自己的記錄即可)、根端口、指定端口;4、設置物理端口的轉發(fā)狀態(tài):br_port_state_selection2.1 br_supersedes_port_info(p, bpdu)/* called under bridge lock */static int br_supersedes_port_info(struct net_bridge_port *p, struct br_config_bpdu *bpdu)      &#

13、160; int t;/*第一步*/        t = memcmp(&bpdu->root, &p->designated_root, ;        if (t < 0)                return 1;        else if (t >

14、 0)                return 0;/*第二步*/        if (bpdu->root_path_cost < p->designated_cost)                return 1;        else if (

15、bpdu->root_path_cost > p->designated_cost)                return 0;/*第三步,要同兩個橋ID比:已記錄的最小發(fā)送ID和自己的ID*/        t = memcmp(&bpdu->bridge_id, &p->designated_bridge, ;       

16、0;if (t < 0)                return 1;        else if (t > 0)                return 0;        if (memcmp(&bpdu->bridge_id, &

17、p->br->bridge_id, )                return 1;/*第四步*/        if (bpdu->port_id <= p->designated_port)                return 1;       

18、; return 0;2.2 br_record_config_information如果檢測到有變動,則刷新自己的記錄先:/* called under bridge lock */static void br_record_config_information(struct net_bridge_port *p, struct br_config_bpdu *bpdu)        p->designated_root = bpdu->root;       

19、; p->designated_cost = bpdu->root_path_cost;        p->designated_bridge = bpdu->bridge_id;        p->designated_port = bpdu->port_id;/*設置時間戳,關于STP的時間處理,后面來分析*/        br_timer_set(&p

20、->message_age_timer, jiffies - bpdu->message_age);p對應的四個成員的概念對照BPDU封包結構,不難理解其含義:        p->designated_root:                指定的根網橋的網橋ID        p->designated_cost :   

21、60;            指定的到根橋的鏈路花銷        p->designated_bridge:                指定的發(fā)送當前BPDU包的網橋的ID        p->designated_port:       

22、        指定的發(fā)送當前BPDU包的網橋的端口的ID2。3 br_configuration_update前面說過,根橋的選舉不是在這里進行,這里進行根端口和指定端口的選舉/* called under bridge lock */void br_configuration_update(struct net_bridge *br)                        b

23、r_root_selection(br);/*選舉根端口*/        br_designated_port_selection(br);/*選舉指定端口*/2.3.1 根端口的選舉br_root_selection根端口的選舉同樣是以上四個步驟,只是有一點小技巧:它逐個遍歷橋的每一個所屬端口,找出一個符合條件的,保存下來,再用下一個來與之做比較,用變量root_port 來標志:/* called under bridge lock */static void br_root_selection(struct net_bridg

24、e *br)        struct net_bridge_port *p;        int root_port;        root_port = 0;/*獲得橋的所屬端口列表*/        p = br->port_list;/*這個循環(huán)非常重要,它遍歷橋的每一個端口,進行以上四步判斷,找到一個,將其“保存”下來,然后再用下一個與

25、保存的相比較,直至遍歷完,找到最優(yōu)的那個,這個“保存”打了引號,是因為它僅僅是記當了端口編號:root_port = p->port_no;,然后再將其傳遞給比較函數br_should_become_root_port*/        while (p != NULL)                 if (br_should_become_root_port(p, root_port)    

26、                   root_port = p->port_no;                p = p->next;                br->root_port = root_port;/*找完

27、了還沒有找到,則認為自己就是根橋*/        if (!root_port)                 br->designated_root = br->bridge_id;                br->root_path_cost = 0;      &#

28、160;  /*否則記錄相應的值*/               else                 p = br_get_port(br, root_port);                br->designated_root = p->designated_ro

29、ot;                br->root_path_cost = p->designated_cost + p->path_cost;        br_should_become_root_port函數用以判斷端口p是否應該變成根端口,與它相比較的是原來那個根端口,函數第二個參數則為此的ID號,在函數中調用 br_get_port獲取該端口:/* called under bridge lock */

30、static int br_should_become_root_port(struct net_bridge_port *p, int root_port)        struct net_bridge *br;        struct net_bridge_port *rp;        int t;        br = p->br;

31、/*若當前端口是關閉狀態(tài)或為一個指定端口,則不參與選舉,返回*/        if (p->state = BR_STATE_DISABLED |            br_is_designated_port(p)                return 0;/*在根端口的選舉中,根橋是沒有選舉權的*/    

32、   if (memcmp(&br->bridge_id, &p->designated_root,  <= 0)                return 0;/*沒有指定等比較的端口ID(因為第一次它初始化為0的)*/        if (!root_port)         

33、0;      return 1;/*獲取待比較的根端口*/        rp = br_get_port(br, root_port);/*又是四大步,像打藍球*/        t = memcmp(&p->designated_root, &rp->designated_root, ;        if (t < 0)   

34、             return 1;        else if (t > 0)                return 0;        if (p->designated_cost + p->path_cost <     &

35、#160;      rp->designated_cost + rp->path_cost)                return 1;        else if (p->designated_cost + p->path_cost >              &#

36、160;  rp->designated_cost + rp->path_cost)                return 0;        t = memcmp(&p->designated_bridge, &rp->designated_bridge, ;        if (t < 0) 

37、;               return 1;        else if (t > 0)                return 0;        if (p->designated_port < rp->designated_port) 

38、              return 1;        else if (p->designated_port > rp->designated_port)                return 0;        if (p->port_id <

39、 rp->port_id)                return 1;        return 0;這樣,遍歷完成后,根端口就被選出來了。2。3。2 指定端口的選舉br_designated_port_selection/* called under bridge lock */static void br_designated_port_selection(struct net_bridge *br)  &#

40、160;     struct net_bridge_port *p;        p = br->port_list;        while (p != NULL)                 if (p->state != BR_STATE_DISABLED &&   

41、0;                br_should_become_designated_port(p)                        br_become_designated_port(p);             

42、  p = p->next;        事實上這個過程與根端口的選舉過程極為類似,沒有分析的必要了!2。3。3 端口狀態(tài)選擇/* called under bridge lock */void br_port_state_selection(struct net_bridge *br)        struct net_bridge_port *p;        p = br->port

43、_list;        while (p != NULL)                 if (p->state != BR_STATE_DISABLED)                         if (p->port_no = br->roo

44、t_port)                                 p->config_pending = 0;                             &

45、#160;  p->topology_change_ack = 0;                                br_make_forwarding(p);                    

46、0;    else if (br_is_designated_port(p)                                 br_timer_clear(&p->message_age_timer);              

47、0;                 br_make_forwarding(p);                         else                     

48、0;           p->config_pending = 0;                                p->topology_change_ack = 0;           

49、0;                    br_make_blocking(p);                                            

50、;            p = p->next;        函數的邏輯結構也很簡單:遍歷整個橋所屬端口:while (p != NULL)如果端口已經DISABLED,則沒有判斷的必要了:p->state != BR_STATE_DISABLED如果端口是根端口,或者是指定端口,就讓讓它forwarding,否則就讓它blocking:             

51、;           if (p->port_no = br->root_port)                                 p->config_pending = 0;           &#

52、160;                    p->topology_change_ack = 0;                                br_make_forwarding(p);   

53、;                      else if (br_is_designated_port(p)                                 br_timer_clear(&p->messa

54、ge_age_timer);                                br_make_forwarding(p);                         else    

55、;                             p->config_pending = 0;                                p-&

56、gt;topology_change_ack = 0;                                br_make_blocking(p);                        /* call

57、ed under bridge lock */static void br_make_forwarding(struct net_bridge_port *p)        if (p->state = BR_STATE_BLOCKING)                 printk(KERN_INFO "%s: port %i(%s) entering %s staten",   &#

58、160;                   p->br->, p->port_no, p->dev->name, "listening");                p->state = BR_STATE_LISTENING;       

59、         br_timer_set(&p->forward_delay_timer, jiffies);        /* called under bridge lock */static void br_make_blocking(struct net_bridge_port *p)        if (p->state != BR_STATE_DISABLED &&

60、0;           p->state != BR_STATE_BLOCKING)                 if (p->state = BR_STATE_FORWARDING |                    p->state = BR_STATE_

61、LEARNING)                        br_topology_change_detection(p->br);                printk(KERN_INFO "%s: port %i(%s) entering %s staten",    

62、;                   p->br->, p->port_no, p->dev->name, "blocking");                p->state = BR_STATE_BLOCKING;        

63、0;       br_timer_clear(&p->forward_delay_timer);        都是設置p->state 相應狀態(tài)位就可以了! 三、選舉完成之后實在不會取名字了,前面分析了br_received_config_bpdu中前面的判斷、刷新、選舉、設置端口狀態(tài)的過程,然而,如果橋認為當前這個BPDU是一個“最優(yōu)的”(即符合前面判斷四步中的某一步),所作的動作不止于此:1、如果因為這個BPDU導致拓樸變化了,如自己以前是根橋,現在不是了,需要發(fā)送T

64、CN包,進行通告;2、需要把這個BPDU包繼續(xù)轉發(fā)下去(如果自己收到數據的端口是根端口的話,那么就有可能有許多交換機(網橋)串在自己的指定端口下邊,總得把這個包能過指定端口再發(fā)給它們吧,否則交換機就不叫交換機了)指下來繼續(xù)看代碼:/*前面說的第1步*/                     if (!br_is_root_bridge(br) && was_root)         &#

65、160;               br_timer_clear(&br->hello_timer);                        if (br->topology_change_detected)            

66、0;                    br_timer_clear(&br->topology_change_timer);                                br_transmit_tcn(br);                             &

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論