Linux網(wǎng)橋?qū)崿F(xiàn)分析-STP的實(shí)現(xiàn)分析_第1頁
Linux網(wǎng)橋?qū)崿F(xiàn)分析-STP的實(shí)現(xiàn)分析_第2頁
Linux網(wǎng)橋?qū)崿F(xiàn)分析-STP的實(shí)現(xiàn)分析_第3頁
Linux網(wǎng)橋?qū)崿F(xiàn)分析-STP的實(shí)現(xiàn)分析_第4頁
Linux網(wǎng)橋?qū)崿F(xiàn)分析-STP的實(shí)現(xiàn)分析_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、#1  Linux網(wǎng)橋?qū)崿F(xiàn)分析-第三部份,STP的實(shí)現(xiàn)分析初步Linux網(wǎng)橋?qū)崿F(xiàn)分析作者:kendo版權(quán)所有,轉(zhuǎn)載請(qǐng)注冊(cè)出處第三部份,STP的實(shí)現(xiàn)分析初步一、STP的框架結(jié)構(gòu)STP發(fā)送的是wikiBPDU/wiki包,該包有所有兩種類型:配置和TCN(拓樸變更通知);對(duì)于BPDU包的處理,有兩種:接收和發(fā)送(廢話),對(duì)于配置類型的BPDU包的發(fā)送,它是靠定時(shí)器來完成的,參BPDU包的幾個(gè)定時(shí)器參數(shù);對(duì)于wikiTCP/wiki類型的BPDU包的發(fā)送,從名字可以看出來,它是當(dāng)發(fā)現(xiàn)拓樸結(jié)構(gòu)發(fā)生變更時(shí)發(fā)送的,如本機(jī)網(wǎng)橋配置的變化,物理接口的變動(dòng),分析其它機(jī)器變動(dòng)后發(fā)出來的STP包

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

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

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

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

6、編號(hào)組成,用于標(biāo)識(shí)某個(gè)橋的某個(gè)端口,后面比較時(shí)好用。生成樹算法就是利用上述四個(gè)參數(shù)在判斷,判斷過程總是相同的:1、確定根橋,橋ID最小的(即把包中的橋ID,同自己以前記錄的那個(gè)最小的橋ID相比,機(jī)器加電時(shí),總是以自己的橋ID為根橋ID)的為根橋;2、確定最小路徑開銷;3、確定最小發(fā)送方ID;4、確定最小的端口ID:這四步非常地重要,后面的所以比較都是這四個(gè)步驟。有了這些概念,來看看對(duì)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)和原先的對(duì)應(yīng)的信息(p),如果需要更新,返回1,相同返回0,不需更新返回-1*/        if (br_supersedes_port_info(p, bpdu)                 /*刷新自己的相關(guān)信息*/                br_record_config_infor

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

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

12、前面說的,根據(jù)四步判斷后選舉根橋(注:根橋不是在這里選舉的,前文說過,它是定時(shí)器定時(shí)發(fā)送BPDU包,然后收到的機(jī)器只需改變自己的記錄即可)、根端口、指定端口;4、設(shè)置物理端口的轉(zhuǎn)發(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;/*第三步,要同兩個(gè)橋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如果檢測(cè)到有變動(dòng),則刷新自己的記錄先:/* 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;/*設(shè)置時(shí)間戳,關(guān)于STP的時(shí)間處理,后面來分析*/        br_timer_set(&p

20、->message_age_timer, jiffies - bpdu->message_age);p對(duì)應(yīng)的四個(gè)成員的概念對(duì)照BPDU封包結(jié)構(gòu),不難理解其含義:        p->designated_root:                指定的根網(wǎng)橋的網(wǎng)橋ID        p->designated_cost :   

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

22、        指定的發(fā)送當(dāng)前BPDU包的網(wǎng)橋的端口的ID2。3 br_configuration_update前面說過,根橋的選舉不是在這里進(jìn)行,這里進(jìn)行根端口和指定端口的選舉/* 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根端口的選舉同樣是以上四個(gè)步驟,只是有一點(diǎn)小技巧:它逐個(gè)遍歷橋的每一個(gè)所屬端口,找出一個(gè)符合條件的,保存下來,再用下一個(gè)來與之做比較,用變量root_port 來標(biāo)志:/* 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;/*這個(gè)循環(huán)非常重要,它遍歷橋的每一個(gè)端口,進(jìn)行以上四步判斷,找到一個(gè),將其“保存”下來,然后再用下一個(gè)與

25、保存的相比較,直至遍歷完,找到最優(yōu)的那個(gè),這個(gè)“保存”打了引號(hào),是因?yàn)樗鼉H僅是記當(dāng)了端口編號(hào):root_port = p->port_no;,然后再將其傳遞給比較函數(shù)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、了還沒有找到,則認(rèn)為自己就是根橋*/        if (!root_port)                 br->designated_root = br->bridge_id;                br->root_path_cost = 0;      &#

28、160;  /*否則記錄相應(yīng)的值*/               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函數(shù)用以判斷端口p是否應(yīng)該變成根端口,與它相比較的是原來那個(gè)根端口,函數(shù)第二個(gè)參數(shù)則為此的ID號(hào),在函數(shù)中調(diào)用 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、/*若當(dāng)前端口是關(guān)閉狀態(tài)或?yàn)橐粋€(gè)指定端口,則不參與選舉,返回*/        if (p->state = BR_STATE_DISABLED |            br_is_designated_port(p)                return 0;/*在根端口的選舉中,根橋是沒有選舉權(quán)的*/    

32、   if (memcmp(&br->bridge_id, &p->designated_root,  <= 0)                return 0;/*沒有指定等比較的端口ID(因?yàn)榈谝淮嗡跏蓟癁?的)*/        if (!root_port)         

33、0;      return 1;/*獲取待比較的根端口*/        rp = br_get_port(br, root_port);/*又是四大步,像打藍(lán)球*/        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;        事實(shí)上這個(gè)過程與根端口的選舉過程極為類似,沒有分析的必要了!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;        函數(shù)的邏輯結(jié)構(gòu)也很簡單:遍歷整個(gè)橋所屬端口:while (p != NULL)如果端口已經(jīng)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);        都是設(shè)置p->state 相應(yīng)狀態(tài)位就可以了! 三、選舉完成之后實(shí)在不會(huì)取名字了,前面分析了br_received_config_bpdu中前面的判斷、刷新、選舉、設(shè)置端口狀態(tài)的過程,然而,如果橋認(rèn)為當(dāng)前這個(gè)BPDU是一個(gè)“最優(yōu)的”(即符合前面判斷四步中的某一步),所作的動(dòng)作不止于此:1、如果因?yàn)檫@個(gè)BPDU導(dǎo)致拓樸變化了,如自己以前是根橋,現(xiàn)在不是了,需要發(fā)送T

64、CN包,進(jìn)行通告;2、需要把這個(gè)BPDU包繼續(xù)轉(zhuǎn)發(fā)下去(如果自己收到數(shù)據(jù)的端口是根端口的話,那么就有可能有許多交換機(jī)(網(wǎng)橋)串在自己的指定端口下邊,總得把這個(gè)包能過指定端口再發(fā)給它們吧,否則交換機(jī)就不叫交換機(jī)了)指下來繼續(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等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論