這三個任務未必是依照 1~3 的順序決定的。
net/bridge/br_private_stp.h
中:
兩者之間欄位可以由 br_record_config_information()
得知:
bridge_id
–- 自己的 BID誰發出這個 BPDU。
root
–- 發送者認為的 Root BID也就是發送者目前看過「最小」的 BID。
root_path_cost
–- 自己到 Root 的成本這個 BPDU 中所記錄的的 bridge_id
到所記錄的 root
所需要的成本。
struct net_bridge_port
每個 port 中,都會紀錄「這個 port 認為的 root bridge」是誰,以及到這個 root bridge 的成本。最後,還有這個 port 認為的 designated port 是誰。這些成員分別是:
path_cost
–- Port 的成本這就是計算 root_path_cost
時,經過這個端口要加上的那個成本。
designated_root
–- 目前看過最小的 BID這個 port 收到的所以 BPDU 中,出現過的最小的 BID。所以可以想像如果一個 port 的 designated_root
被更新,下一步就是拿回去跟 bridge 目前已知的 root bridge 做比較。
designated_cost
–- Port 到 Root Bridge 的最小成本從這個 port 出發到 root bridge 所需要的最小成本。所以所有的 port 中,具有最小 designated_cost
的那個 port 就會變 root port。
designated_bridge
與 designated_port
–- 目前的 Designated Portdesignated_bridge
與 designated_port
這兩個成員指得是「目前找到的 designated port 是哪一個 bridge 的哪個 port」。因為 一個 BPDU 會紀錄這個 BPDU 從哪個 Bridge 的哪個 Port 發出,而一個 Port 如果要收到一個 BPDU,就要跟發出 BPDU 的那個 Port 處於同一個 LAN 上。所以藉由比較這個 BPDU 上的 root_path_cost
,就可以知道自己是否要從 designated port 「退位」,讓給那個發出 BPDU 的 port。
因此,對於一個 designated port,看看他的 designated_bridge
與 designated_port
是否恰好就是「自己所屬的 bridge」與「自己的 port ID」,就可以確認自己是不是 designated port。而這也可以在 br_is_designated_port()
的實作中看到:
這時可以觀察到:一個 bridge 中的所有 port 中:
designated_root
的那個 port,就會是 root port。designated_cost
的 port 就會是 root port。port_id
的,就會是 root port。struct net_bridge
每個 bridge 也會維持自己的資料結構。在 net/bridge/br_private.h
中。其中,跟 STP 有關的部分:
designated_root
–- Root Bridge 的 BIDroot_port
–- 自己的哪個 Port 是 Root Port?首先,每個 bridge 都往自己的所有端口廣播「Root BID 為自己 BUD」 BPDU,接著開始接收旁邊廣播來的 BPDU。接下來每收到一個 BPDU,就依照現在大家正在「尋找 Root Bridge」「決定 Root Port」「決定 Designated Port」的哪個階段,來決定收到 BPDU 時該做什麼反應。:
這是第一次廣播之後開始發生的事情,所以這是最先發生的。如果現在大家正在決定哪一個 bridge 是 root bridge,或者是說大家正在找「哪個 bridge 有最小的 BID」,那麼就會發生以下的事情:
首先,拿到 BPDU 時,會先看看上面是不是個更好的情報來源。這個「更好」包含:
root
成員)是否比自己現在認為的 root(port 自己的 designated_root
成員)還要小。root_path_cost
更小。這個比較發生在 br_supersedes_port_info()
中:
如果發現 BPDU 上面記錄著更好的路徑(也就是上面這個函式回傳 1
時),那麼就把這個 BPDU 上面的資訊更新到這個 port 上,並且叫 bridge 更新自己的 root port。其中,「把 BPDU 更新到 port 上」是由 br_record_config_information()
來做:
其中,一個 port 的 designated_*
成員,指得是:如果指定從這個 port 送封包給這個 port 所認為的 root,那麼 root_path_cost
是多少?以及這個風包送出去之後,第一個會送給哪個 bridge 的哪個 port?等等。
而更新到 port 上之後,就再看看現在這個 bridge 上的所有 port 中,會不會有更適合的 port 能夠當 root port 或 designted port。這個也就是接下來的 br_configuration_update()
要做的事:
br_root_selection()
其中,br_root_select()
做的事情就是把 bridge 上的每個 root port 看一遍,看看有哪個比現在的 root port 更好。如果沒有 root port,就表示現在這個 bridge 是 root bridge,所以就把自己變成 root bridge; 反之,就把 bridge 的 root port 設定成剛剛找到的那個 root port:
而從眾多 port 中挑出 root port 的標準,就是看每個 port 的 designated_*
成員。「以一個 port 為出發點,可以走到的最佳路徑」。如果發現從某一個 port 出發到 root 的路徑比現在 bridge 上的路徑更好,那就表示這個 port 應該要成為新的 root port,所以就回傳 1
:
root_path_cost
」加上「收到端口的成本」,看看跟目前的 root_path_cost
比起來是否更低。如果成本更低,就 root port 更新成現在這個端口。br_designated_port_selection()
LAN 上的所有 port 會聽到所有其他 port 送出的 BPDU。如果發現這個「目前聽到所有其他 port 的最小 root_path_cost
」比「經過自己會有的 root_path_cost
」還要小,那這個 port 就有資格成為 designated port:
而「成為 designated port」的意思就是「把自己到 root bridge 的成本,從『打聽到的最小值』變成『走自己的 bridge 的成本』」:
在這個過程中,只有 root port 的 BPDU 能夠暢行無阻地一路被所有 Bridge 「複誦」過去。
如果現在是「所有人正在決定自己的哪個 port 要當 root port」,那麼拿到 BPDU 時,會發生下面的事:
root_path_cost
的 BPDU 廣播出去。把新的 BPDU 廣播出去時,其它收到的 bridge 就繼續做上面這些事。