Linux STP介紹


1. 介紹

STP(Spanning Tree Protocol)即生成樹協議,標准為IEEE802.1D-1998
STP是一種二層冗余技術,利用STA算法構建一個邏輯上沒有環路的樹形網絡拓撲結構,並且可以通過一定的方法實現路徑冗余

STP

2. 概念

2.1 角色

生成數有如下角色

 - 根橋(Root Bridge) RB, 橋ID最小的橋
- 根端口(Root Port) RP, 該端口到達根橋的路徑是該端口所在網橋到達根橋的最佳路徑
- 指定端口(Designated Port)DP, 每一個網段選擇到根橋最近的網橋作為指定網橋, 該網橋到這一網段的端口為指定端口
- 可選端口(Alternated Port)AP, 即阻塞端口, 既不是指定端口, 也不是根端口的端口

2.2 端口狀態

STP端口狀態有如下幾種

 - 斷開(Disable):     不收發任何報文
- 阻塞(Blocking): 不接收或轉發數據, 接收但不發送BPDU, 不進行地址學習
- 監聽(Listening): 不接收或轉發數據, 接收並發送BPDU, 不進行地址學習
- 學習(Learning): 不接收或轉發數據, 接收並發送BPDU, 開始地址學習
- 轉發(Forwarding): 接收並轉發數據, 接收並發送BPDU, 進行地址學習

一個網橋開啟STP后,端口會經歷如下過程:

Blocking(20s) –> Listening(15s) –> Learning(15s) –> Forwarding

這樣大約50秒的時間非根端口轉變成為根端口或指定端口PortStates

2.3 相關參數

2.3.1 網橋參數

Bridge Identifier:        標識本網橋, 由網橋的優先級(2 bytes)和網橋的MAC(6 bytes)組成
Root Path Cost:           從非根橋到根橋的路徑開銷的總和
Root Port:                根端口, RP
Max Age:                  在協議的配置信息被丟棄之前收到的配置信息保留的時間(默認20s)
Hello Time:               對一個想變成橋或者是根橋的橋在固定的時間發送的配置BPDU信息(默認2s)
Forward Delay:            從Listening到Learning和從Learning到Forwarding花費的時間(默認15s)
Bridge Max Age:           橋作為根或想成為根橋的橋標識的它作為根橋的最大年齡
Bridge Hello Time:        非根橋向根橋發送TCN BPDU的時間間隔
Bridge Forward Delay:     和上面介紹的Forward Delay值一樣
Topology Change Detected: 用來標識網絡拓撲結構改變的布爾變量
Topology Change:          參數設置表示拓撲改變
Topology Change Time:     根橋產生配置消息指明拓撲改變的時間間隔
Hold Time:                在這個時間間隔至少應該收到一個配置BPDU信息

2.3.2 網橋時間參數

Hello Timer:                        根橋定時傳輸配置BPDU信息的時間間隔
Topology Change Notification Timer: 如果沒收到拓撲改變回應消息便會定時發送拓撲改變通知
Topology Change Time:               定時發送拓撲改變通知來通知橋進行重配

2.3.3 端口參數

Port Identifier:             橋的端口ID, 由優先級和端口號組成
Port State:                  端口狀態
Path Cost:                   本端口的路徑開銷(see tips below)
Designated Root:             根橋的橋ID
Designated Cost:             從這個端口到根橋的路徑開銷
Designated Bridge:           指定橋的橋ID
Designated Port:             指定橋中和它交互的端口ID
Topology Change Acknowledge: 設置來回應拓撲改變通知
Configuration Pending:       設置表示在Holdtimer超時后應該傳輸配置BPDU信息
Change Detection Enabled:    表示是否理會拓撲改變通知

2.3.4 端口時間參數

Message Age Timer:   表示超時丟棄協議信息的時間
Forward Delay Timer: 和端口狀態改變的時間值有關
Hold Timer:          在這個時間間隔至少應該收到一個配置BPDU信息

tips: 關於路徑開銷,可參考<IEEE802.1t路徑開銷列表>
通常根據端口的帶寬不同,Path Cost值也不同:
• 10 Mb/s: 100
• 100 Mb/s: 19
• 1000 Mb/s: 4
• 10000 Mb/s: 2

2.4 BPDU

2.4.1 介紹

STP的數據單元稱為BPDU(Bridge Protocol Data Unit)
BPDU是網橋間信息交流的報文,目標MAC地址為:01-80-C2-00-00-00

網橋之間定期發送BPDU包,交換STP配置信息,以便能夠對網絡的拓撲、花費或優先級的變化做出及時的響應

BPDU報文在直連的兩個網橋或多個網橋內交換,不能被轉發
沒有運行STP協議的網橋將把BPDU報文當作普通業務報文轉發

BPDU被封裝在LLC的Payload中

下面是一個C BPDU

stp_packet 

2.4.2 類型

BPDU有三種類型

 - Configuration BPDU: 即C BPDU, 包含配置信息的BPDU包
- Topology Change Notification BPDU: 即TCN BPDU, 當檢測到網絡拓撲結構變化時發送拓撲變化通知BPDU
- Topology Change Notification Acknowledgment: 即TCA BPDU(TCA flag置1的C BPDU)

BPDU報文格式如下

bpdu_field

2.4.3 發送與接收

C BPDU:

只有RB發送C BPDU,它有一個Hello Timer,當這個定時器expire的時候產生一個BPDU的包
而其他的non-RB在他們的RP中收到這些包之后進行中繼,中繼的過程中對BPDU中的各項值根據自身的情況進行更新

TCN BPDU:
當某個non-RB檢測到拓撲變化后,該br會通過RP向RB方向發送TCN BPDU,其他br從它的DP接收到TCN BPDU時,首先從該DP上回應一個TCA BPDU,然后將該TCN BPDU從RP向RB方向發送, 這樣TCN BPDU最后會到達RB

RB則會發出一個C BPDU(topology change置1),表示發現拓撲變化,這個包會被所有br轉發,傳遍全網,這樣所有br都得知拓撲變化,然后做出相應的動作(修改ageing timer: 5m->15s)

該過程如下圖所示:

tcn_bpdu

TIP: C BPDU是從RB往樹的各個方向傳送;TCN BPDU則是從樹的某個br上行直至RB

2.5 選舉

2.5.1 根橋的選舉

網橋初始化以后,都認為自己是Root Bridge,在它認為的指定端口上,周期性的發送C BPDU直到收到BridgeID更小的網橋信息,才直到自己不是根網橋

或者由於配置管理(端口使能,設置網橋優先級等),端口狀態改變,也會引起Root Bridge的重新選舉

2.5.2 根端口的選擇

非根橋的其他網橋將各自選擇一條到Root Bridge代價最小的路徑,相應端口的角色就成為根端口

2.5.3 指定端口的選擇

根端口選擇以后,選擇到根橋路徑開銷最小的端口作為指定端口

2.5.4 可選端口的選擇

端口enable,參與選舉的拓撲計算,既不是根端口,也不是指定端口,那就是可選端口了

2.5.5 選擇過程

選舉過程如下所示

選舉根橋 -> 根端口 -> 指定端口 -> 其余為阻塞端口

生成樹經過一段時間(默認值是30秒左右)穩定之后,所有端口要么進入轉發狀態,要么進入阻塞狀態
STP BPDU仍然會定時從各個網橋的指定端口發出,以維護鏈路的狀態
如果網絡拓撲發生變化,生成樹就會重新計算,端口狀態也會隨之改變

stp_selection

TIP:
網橋接受BPDU時開銷值增加,發送BPDU時開銷值不變
只有根橋是沒有根端口的,根橋的所有端口都是指定端口
選舉根端口,比較接收的BPDU;
選舉指定端口,比較發送的BPDU.

3. 實現

3.1 數據結構

net_bridge:  網橋STP相關參數

struct net_bridge
{
    ...
    /* STP */
    bridge_id        designated_root;  /* RB ID */
    bridge_id        bridge_id;        /* ID */
    u32              root_path_cost;   /* 路徑開銷 */
    unsigned long    max_age;          /* 配置信息保留時間 */
    unsigned long    hello_time;
    unsigned long    forward_delay;
    unsigned long    bridge_max_age;
    unsigned long    ageing_time;
    unsigned long    bridge_hello_time;
    unsigned long    bridge_forward_delay;

    u8               group_addr[ETH_ALEN];
    u16              root_port;        /* 本網橋的根端口 */

    enum {
        BR_NO_STP,      /* no spanning tree */
        BR_KERNEL_STP,  /* old STP in kernel */
        BR_USER_STP,    /* new RSTP in userspace */
    } stp_enabled;

    unsigned char     topology_change;
    unsigned char     topology_change_detected;

    struct timer_list    hello_timer;
    struct timer_list    tcn_timer;
    struct timer_list    topology_change_timer;
    struct timer_list    gc_timer;
};

net_bridge_port:  網橋端口STP相關參數

struct net_bridge_port
{
    /* STP */
    u8                priority;
    u8                state;
    u16               port_no;
    unsigned char     topology_change_ack;
    unsigned char     config_pending;
    port_id           port_id;             /* 本端口的端口ID */
    port_id           designated_port;     /* 發送當前BPDU包的端口ID */
    bridge_id         designated_root;     /* 根橋的網橋ID */
    bridge_id         designated_bridge;   /* 發送當前BPDU包的網橋ID */
    u32               path_cost;           /* 本端口的路徑開銷 */
    u32               designated_cost;     /* 到根橋的路徑開銷 */
    unsigned long     designated_age;

    struct timer_list        forward_delay_timer;
    struct timer_list        hold_timer;
    struct timer_list        message_age_timer;
};

br_config_bpdu:  BPDU包

struct br_config_bpdu {
    unsigned int topology_change:1;
    unsigned int topology_change_ack:1;
    bridge_id    root;
    int          root_path_cost;
    bridge_id    bridge_id;
    port_id      port_id;
    int          message_age;
    int          max_age;
    int          hello_time;
    int          forward_delay;
};

可以發現,br_config_bpdu和C BPDU報文格式對照可以發現,缺少 Protocol ID、Version、Message Type和Flags
因為Message Type基本在使用的時候可以確定,而Flags則可由topology_change和topology_change_ack來確定
具體可參考函數br_send_config_bpdu()的實現

3.2 STP模塊

3.2.1 基本使用

/*
 * 新增網橋
 * br_dev_setup()
 */
# brctl addbr br0

/*
 * 向網橋新增端口
 * br_add_if() -> new_nbp() -> br_init_port()
 */
# brctl addif br0 eth0

/* 
 * 啟用和禁用STP
 * on  -> br_stp_start() -> br_port_state_selection()
 * off -> br_stp_stop()
 */
# brctl stp br0 <on|off>

3.2.2 數據通路

static const struct stp_proto br_stp_proto = {
    .rcv = br_stp_rcv,
};
static int __init br_init(void)
{
    stp_proto_register(&br_stp_proto);
    ......
}

參考:
<Linux Bridge STP HOWTO>
<Spanning Tree Protocol (STP)>
<Linux的網橋中的STP的實現分析初步>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM