บทความ อีเทอร์เน็ต ทิ้งข้อเท็จจริงข้อหนึ่งไว้โดยยังไม่ได้ บอกว่ามันอันตรายแค่ไหน
เฟรมอีเทอร์เน็ตไม่มีฟิลด์อายุ
แพ็กเก็ต IP มี TTL ทุกเราเตอร์ที่ส่งต่อจะลดค่าลงหนึ่ง พอเหลือศูนย์ก็ถูกทิ้ง นั่นคือเหตุผลที่ traceroute ทำงานได้ และเป็นเหตุผลที่ แพ็กเก็ตที่หลงทางในอินเทอร์เน็ตตายเองเสมอ
เฟรมอีเทอร์เน็ตไม่มีอะไรแบบนั้นเลย ไม่มีฟิลด์ไหนให้ลดค่า ไม่มีเงื่อนไขไหนที่ทำให้ สวิตช์ตัดสินใจทิ้งเฟรมเพราะมันเดินทางมานานพอแล้ว
หน้านี้คือเรื่องของสิ่งที่ต้องสร้างขึ้นมาเพราะฟิลด์นั้นไม่มี
ปัญหา — เฟรมเดียวก็พอ
บทความ MAC address อธิบายไว้ว่าสวิตช์ทำสองอย่าง — จำว่า MAC ไหนอยู่พอร์ตไหน และถ้าไม่รู้ว่าปลายทางอยู่ไหน ก็ส่งออกทุกพอร์ตยกเว้น พอร์ตที่รับมา ส่วน broadcast นั้นส่งออกทุกพอร์ตเสมอ ไม่มีข้อยกเว้น
เอาสองข้อนั้นมารวมกับสายที่ต่อเป็นวง แล้วให้เครื่องหนึ่งส่ง broadcast ออกมา หนึ่งเฟรม
สวิตช์ B ส่งต่อไป A และ C · A ส่งต่อไป C · C ส่งต่อไป A และกลับมา B · แล้ววนต่อ พร้อมกันทั้งสองทิศทาง จำนวนเฟรมเพิ่มขึ้นทุกรอบ และไม่มีอะไรมาหยุด
นี่ไม่ใช่ "เครือข่ายช้าลง" แต่คือเครือข่ายตาย ภายในไม่กี่วินาที ซีพียูของสวิตช์ เต็ม สายเต็ม และเครื่องทุกเครื่องบนวงนั้นก็ยุ่งอยู่กับการอ่านเฟรมเดิมซ้ำ ๆ
แถมยังมีผลข้างเคียงที่ทำให้แก้ยากขึ้นไปอีก — เฟรมเดียวกันนั้นวิ่งเข้าสวิตช์ทาง พอร์ตต่างกันสลับไปมา ตาราง MAC จึงเขียนทับตัวเองไม่หยุด สวิตช์ไม่ได้แค่ท่วม เครือข่าย มันลืมว่าอะไรอยู่ที่ไหนไปด้วย
ถ้ายังไม่เคยดูของจริง เริ่มตรงนี้
เครื่อง Mac ที่กำลังอ่านหน้านี้อยู่มีบริดจ์ที่รองรับ STP อยู่แล้ว
$ ifconfig bridge0
bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST>
Configuration:
id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
member: en1 flags=3<LEARNING,DISCOVER>
สิ่งที่ควรสังเกตคือค่าที่เป็นศูนย์ทั้งแถว hellotime 0 fwddelay 0 maxage 0 และ แฟล็กของ member ที่มีแค่ LEARNING,DISCOVER ไม่มีคำว่า STP
แปลว่าบริดจ์ตัวนี้ไม่ได้รัน STP อยู่ ซึ่ง man ifconfig บอกไว้ตรง ๆ ว่า -stp คือค่าตั้งต้นของทุกอินเทอร์เฟซที่ถูกเพิ่มเข้าบริดจ์ ฟิลด์ proto stp ที่พิมพ์ออกมานั้นบอกว่ามันจะใช้โพรโทคอลไหนถ้าเปิด ไม่ได้บอกว่าเปิดอยู่
บนสวิตช์จริงคำสั่งที่ตอบทุกอย่างคือ show spanning-tree ซึ่งจะใช้ตลอดทั้งหน้านี้
STP ไม่ได้กำจัดลูป มันปิดพอร์ต
นี่คือจุดที่คนเข้าใจผิดกันมากที่สุด และเป็นจุดที่ต้องเข้าใจให้ตรงก่อนอย่างอื่น
STP ไม่ได้ทำให้ลูปในสายหายไป สายยังเสียบอยู่ครบทุกเส้น สิ่งที่มันทำคือ เลือกพอร์ตบางพอร์ตมาสั่งห้ามส่งข้อมูล จนกราฟที่เหลือไม่มีวงอีกต่อไป
คำว่า spanning tree มาจากทฤษฎีกราฟตรง ๆ — ต้นไม้ที่แผ่ถึงทุกจุดยอด คุณสมบัติ ของต้นไม้คือเชื่อมทุกจุดถึงกันโดยไม่มีวง ซึ่งพอดีกับสิ่งที่ต้องการเป๊ะ
และนี่คือค่าใช้จ่ายที่หนีไม่พ้น สายที่จ่ายเงินซื้อมาแล้วต่อไว้แล้ว ห้ามใช้ ในเครือข่ายที่แต่ละสวิตช์มีสายขึ้นสองเส้นเพื่อความทนทาน ครึ่งหนึ่งของแบนด์วิดท์ ที่ลงทุนไปนั่งเฉย ๆ ตลอดเวลา นั่นคือราคาที่จ่ายให้ความปลอดภัย และเป็นแรงผลักดัน ของทุกอย่างที่พัฒนามาทีหลัง
1985 — โจทย์ที่ Radia Perlman ได้รับ
Radia Perlman ทำงานอยู่ที่ Digital Equipment Corporation และได้รับโจทย์ว่า ทำอย่างไรให้บริดจ์หลายตัวต่อกันเป็นโทโพโลยีอะไรก็ได้ แล้วยังทำงานถูกต้อง
ผลลัพธ์คือเปเปอร์ An Algorithm for Distributed Computation of a Spanning Tree in an Extended LAN ตีพิมพ์ใน Proceedings of the ninth symposium on Data communications ปี 1985 หน้า 44 ถึง 53
เงื่อนไขที่ทำให้โจทย์นี้ยากไม่ใช่การหา spanning tree — อัลกอริทึมหา spanning tree มีมาก่อนหน้านั้นนานแล้ว ความยากคือต้องหาแบบกระจาย ไม่มีตัวไหนเห็นภาพ รวม ไม่มีตัวไหนรู้ว่ามีสวิตช์กี่ตัว และต้องได้คำตอบเดียวกันทุกตัว
สิ่งที่เธอเขียนคือกลไกที่ยังใช้อยู่ในสวิตช์ทุกตัวบนโลกวันนี้ IEEE รับไปทำเป็น มาตรฐาน 802.1D ในปี 1990
เปเปอร์ฉบับนี้ยังมีของแถมที่รู้จักกันในวงการ — Perlman เขียนบทกวีชื่อ Algorhyme ประกอบไว้ในนั้นด้วย
แนวคิดการออกแบบ — ทำไมหน้าตาถึงออกมาแบบนี้
ส่วนนี้มีค่ากับคนที่อ่านจบแล้วจะไปออกแบบอะไรของตัวเองมากกว่ารายละเอียดฟิลด์
ต้องทำงานได้โดยไม่ต้องตั้งค่าอะไรเลย
บริดจ์ในยุคนั้นถูกขายให้คนที่ไม่มีทีมเครือข่าย ถ้าโพรโทคอลต้องตั้งค่าก่อนถึงจะ ปลอดภัย มันจะไม่ปลอดภัยในสถานที่ส่วนใหญ่ ทุกค่าจึงมีค่าตั้งต้นที่ใช้ได้ทันที และค่าตั้งต้นถูกเลือกให้ปลอดภัยไว้ก่อน ไม่ใช่เร็วไว้ก่อน
ไม่มีศูนย์กลาง จึงต้องสร้างศูนย์กลางขึ้นมา
ทุกตัวเท่าเทียมกันหมดตอนเริ่ม แต่การคำนวณต้นไม้ต้องมีราก วิธีแก้คือให้ทุกตัว ประกาศตัวเองเป็นรากก่อน แล้วยอมแพ้เมื่อได้ยินตัวที่ "ดีกว่า" นิยามของดีกว่าคือ เลขที่น้อยกว่า ซึ่งเป็นเกณฑ์ที่ทุกตัวคำนวณเองได้โดยไม่ต้องถามใคร
ข้อมูลต้องหมดอายุเองได้
สายที่ขาดไม่ส่งสัญญาณมาบอกว่ามันขาด บริดจ์จึงรู้ได้ทางเดียวคือไม่ได้ยินอะไร อีกเลย ทุกข้อมูลจึงมีอายุ ถ้าไม่มีของใหม่มาต่ออายุ ของเก่าจะตายไปเอง
นี่คือรากของความช้าทั้งหมดที่จะพูดถึงต่อไป การรอให้แน่ใจว่าเงียบจริงต้องรอนาน กว่าที่ข้อความหายไปหนึ่งครั้ง
เมื่อยังไม่แน่ใจ ให้เลือกข้างที่ไม่ส่ง
พอร์ตที่เพิ่งขึ้นมาจะไม่ส่งข้อมูลทันที มันจะรอ ฟัง แล้วค่อยส่ง เพราะผลของการ เดาผิดสองแบบไม่เท่ากัน — เดาผิดแล้วไม่ส่ง เสียเวลาไม่กี่วินาที เดาผิดแล้วส่ง เครือข่ายทั้งวงล่ม
กลไก — กฎสามข้อ แล้วจบ
ทั้งโพรโทคอลสรุปได้เป็นสามข้อ
หนึ่ง เลือก root bridge หนึ่งตัวต่อเครือข่าย ตัวที่ bridge ID น้อยที่สุดชนะ
สอง สวิตช์ที่ไม่ใช่ root เลือก root port หนึ่งพอร์ต คือพอร์ตที่ cost รวมไป ถึง root ต่ำที่สุด
สาม แต่ละสายเลือก designated port หนึ่งฝั่ง คือฝั่งที่ใกล้ root กว่า
พอร์ตที่ไม่ได้บทบาทไหนเลย ถูกปิด ไม่มีข้อสี่ กฎสามข้อนี้รับประกันเองว่าสิ่ง ที่เหลือเป็นต้นไม้เสมอ
bridge ID กว้าง 8 ไบต์ และมันเปลี่ยนความหมายไปแล้ว
priority 2 bytes
MAC 6 bytes
-------
8 bytes
ค่าตั้งต้นของ priority คือ 32768 และตั้งได้เป็นช่วง 0 ถึง 61440 ทีละ 4096 เท่านั้น
ตัวเลข 4096 นั้นไม่ได้มาลอย ๆ 802.1t แบ่งสองไบต์นั้นใหม่ เป็น priority 4 บิต กับ system ID extension 12 บิต 12 บิตหลังถูกใช้เก็บหมายเลข VLAN หรือหมายเลข instance ทำให้ทุกอินสแตนซ์มี bridge ID ต่างกันโดยไม่ต้องใช้ MAC คนละอัน
4 bits priority x 4096 = ขยับได้ทีละ 4096
12 bits ext -> 0 ถึง 4095 คือเลข VLAN
ผลที่เห็นบนหน้าจอจริงคือเลขแปลก ๆ อย่าง 32778 ซึ่งอ่านออกได้ทันทีเมื่อรู้ที่มา
32778 = 32768 + 10 priority 32768 ที่ VLAN 10
24586 = 24576 + 10 priority 24576 ที่ VLAN 10 (24576 = 6 x 4096)
path cost คือส่วนที่ต้องเขียนใหม่สองครั้ง
802.1D ฉบับแรกให้ cost มาจากสูตร 1000 หารด้วยความเร็วเป็น Mbps
10 Mbps -> 1000/10 = 100
100 Mbps -> 1000/100 = 10
1 Gbps -> 1000/1000 = 1
10 Gbps -> 1000/10000 = 0.1
บรรทัดสุดท้ายคือจุดที่สูตรพัง cost เป็นจำนวนเต็ม ค่าที่น้อยกว่า 1 ไม่มีที่อยู่ และต่อให้ปัดเป็น 1 มันก็แยกไม่ออกจากกิกะบิต
802.1D ฉบับ 1998 จึงทิ้งสูตรแล้วใช้ตารางแทน ค่าที่กำหนดไว้เช่น 10 Mbps เป็น 100 · 100 Mbps เป็น 19 · 1 Gbps เป็น 4 เลข 19 ที่ดูไม่เข้าพวกนั้นถูกเลือกมาเพื่อให้ ช่องว่างระหว่างชั้นความเร็วยังใช้งานได้ ไม่ได้มาจากสูตรใด
แล้วก็ยังไม่พอ เพราะ 802.1D ฉบับ 1998 จำกัด path cost ไว้ที่จำนวนเต็มไม่มี เครื่องหมาย 16 บิต คือ 65535 พอความเร็วขึ้นไปอีก ช่วงนั้นก็แคบเกิน 802.1t จึงเปิดใช้ 32 บิตเต็มที่ BPDU มีอยู่แล้ว และให้ตารางใหม่
10 Mbps -> 2,000,000
100 Mbps -> 200,000
1 Gbps -> 20,000
10 Gbps -> 2,000
และค่าพวกนี้เป็นแค่ "ค่าที่แนะนำ" ไม่ใช่ข้อบังคับ RFC 4188 ซึ่งเป็น MIB ของ บริดจ์เขียนไว้ตรง ๆ ว่า 802.1D-1998 แนะนำให้ค่าตั้งต้นแปรผกผันกับความเร็ว เท่านั้น
ตรวจกับของจริงแล้วเห็นความต่างทันที เคอร์เนล Linux ที่ net/bridge/br_if.c ให้กิกะบิตเป็น 5 ไม่ใช่ 4
SPEED_10000 -> 2
SPEED_5000 -> 3
SPEED_2500 -> 4
SPEED_1000 -> 5
SPEED_100 -> 19
SPEED_10 -> 100
เหตุผลอ่านออกจากตารางเอง ถ้ากิกะบิตเป็น 4 ตามมาตรฐาน ก็ไม่เหลือเลขให้ 2.5G Linux เลื่อนกิกะบิตลงมาหนึ่งขั้นเพื่อเปิดที่ว่างให้ความเร็วที่เกิดทีหลัง
บทเรียนที่ใช้ได้กว้างกว่าเรื่อง STP — เมื่อสองอุปกรณ์คนละยี่ห้อคิด cost ไม่ตรงกัน ต้นไม้ที่ได้จะไม่ใช่ต้นไม้ที่คุณคิดว่าจะได้ อย่าอ่านแค่เอกสาร มาตรฐาน ให้อ่านค่าที่อุปกรณ์ตรงหน้ารายงานออกมา
อ่าน BPDU ให้ออกทุกฟิลด์
ข้อความที่บริดจ์คุยกันเรียกว่า BPDU ส่งไปที่ MAC ปลายทาง 01:80:c2:00:00:00 และใช้ LLC SAP 0x42 ทั้งต้นทางและปลายทาง
ที่อยู่นั้นถูกเลือกมาด้วยเหตุผล มันอยู่ในช่วงที่บริดจ์ต้องไม่ส่งต่อ ข้อความ STP จึงเดินได้แค่หนึ่งฮอปเสมอ คุยกับเพื่อนบ้านโดยตรงเท่านั้น โพรโทคอลที่ทำหน้าที่ป้องกันลูปจะเป็นตัวที่วนเองไม่ได้
Configuration BPDU มีสิบสองฟิลด์ รวมกันได้ 35 ไบต์พอดี
off field len meaning
0 Protocol Identifier 2 always 0x0000
2 Protocol Version 1 0 in 802.1D
3 BPDU Type 1 0x00 config, 0x80 TCN
4 Flags 1 bit 0 = TC, bit 7 = TC ack
5 Root Identifier 8 who everyone calls root
13 Root Path Cost 4 sender's own cost to root
17 Bridge Identifier 8 who sent this frame
25 Port Identifier 2 which port sent it
27 Message Age 2 grows on every hop
29 Max Age 2 root's value, everyone obeys
31 Hello Time 2 root's value, everyone obeys
33 Forward Delay 2 root's value, everyone obeys
---
35
ตัวเลขนี้ตรวจได้จากซอร์สจริง ใน net/bridge/br_stp_bpdu.c ของเคอร์เนล Linux บัฟเฟอร์ประกาศไว้ว่า unsigned char buf[35] และส่งด้วย br_send_bpdu(p, buf, 35) ส่วน TCN BPDU ใช้ buf[4] แล้วส่งด้วยความยาว 4
สามฟิลด์ที่ควรอ่านให้ลึกกว่าชื่อ
Message Age คือฟิลด์ที่ทำหน้าที่แทน TTL ที่เฟรมอีเทอร์เน็ตไม่มี มันเป็นฟิลด์ เดียวในนี้ที่บริดจ์กลางทางบวกค่าเพิ่มก่อนส่งต่อ พอบวกจนเกิน Max Age ข้อมูลชุด นั้นถูกทิ้ง สังเกตว่าอีเทอร์เน็ตไม่ได้ตัวนับอายุคืนมา — โพรโทคอลนี้สร้างตัวนับ ของตัวเองขึ้นมาใช้เฉพาะกับข้อความของตัวเอง
สามฟิลด์ timer ท้ายสุดเป็นค่าของ root ไม่ใช่ค่าของผู้ส่ง ตั้ง max age ที่ สวิตช์ตัวหนึ่งแล้วไม่มีอะไรเกิดขึ้นเป็นเรื่องปกติ เพราะถ้ามันไม่ใช่ root ค่าที่ ตั้งไว้จะถูกค่าจาก root ทับทุกครั้งที่ BPDU มาถึง ค่าที่ตั้งจะมีผลก็ต่อเมื่อมัน ได้เป็น root เท่านั้น
ทั้งสี่ฟิลด์เป็นเลข 16 บิต หน่วยหนึ่งในสองร้อยห้าสิบหกวินาที เห็นได้ในซอร์ส เดียวกันที่ #define STP_HZ 256 แปลว่า 20 วินาทีถูกส่งไปเป็นเลข 5120 และค่าที่ มากที่สุดที่ฟิลด์นี้เก็บได้คือ 65535 หารด้วย 256 ประมาณ 256 วินาที
ห้าสถานะ และห้าสิบวินาที
พอร์ตใน 802.1D มีห้าสถานะ และสามในนั้นคือการรอ
disabled ปิดอยู่ ไม่ทำอะไรเลย
blocking รับ BPDU อย่างเดียว ไม่ส่งข้อมูล ไม่จำ MAC
listening ร่วมคำนวณต้นไม้แล้ว แต่ยังไม่จำ MAC และยังไม่ส่ง
learning เริ่มจำ MAC แล้ว แต่ยังไม่ส่ง
forwarding ส่งข้อมูลได้ตามปกติ
ค่าตั้งต้นของ timer ทั้งสามคือ hello 2 วินาที · max age 20 · forward delay 15 ตรวจได้จาก man ifconfig บนเครื่องนี้เอง ซึ่งระบุช่วงที่ตั้งได้ไว้ด้วย
maxage default 20 min 6 max 40
fwddelay default 15 min 4 max 30
hellotime default 2 min 1 max 2
priority default 32768 min 0 max 61440
สามบรรทัดแรกตรงกับช่วงที่ RFC 4188 กำหนดไว้เป็นหน่วยหนึ่งในร้อยวินาที คือ 600 ถึง 4000 · 400 ถึง 3000 · และ 100 ถึง 1000
แต่บรรทัด hellotime ไม่ตรง RFC 4188 ให้ช่วง 1 ถึง 10 วินาที ส่วน macOS ให้แค่ 1 ถึง 2 นี่คือเหตุผลที่ต้องอ่าน man page ของเครื่องที่กำลังนั่งอยู่ ไม่ใช่จำจากมาตรฐาน
เวลาที่เสียไปคำนวณตรง ๆ ได้
max age expiry 20
listening 15
learning 15
--
50 seconds
ห้าสิบวินาทีคือกรณีที่สายที่ขาดไม่ใช่สายของตัวเอง ต้องรอให้ข้อมูลเก่าหมดอายุ ก่อนจึงเริ่มนับ ถ้าเป็นสายของตัวเองที่ขาด รู้ได้ทันทีจากสัญญาณไฟฟ้า ไม่ต้องรอ max age เหลือ 15 บวก 15 เป็น 30 วินาที
ทำไมถึงต้องช้าขนาดนั้น เพราะบริดจ์แยกไม่ออกระหว่าง "ไม่ได้ยินเพราะสายขาด" กับ "ไม่ได้ยินเพราะ BPDU หายไปหนึ่งใบ" เมื่อหลักฐานเหมือนกันแต่ผลต่างกันมหาศาล ทางเดียวที่ปลอดภัยคือรอให้นานพอจนแน่ใจ
ห้าสิบวินาทีในปี 1990 ยอมรับได้ ในเครือข่ายที่มีโทรศัพท์และวิดีโอวิ่งอยู่ ยอมรับไม่ได้ ทุกอย่างที่พัฒนาต่อจากนี้คือความพยายามลดตัวเลขนี้
ทุกขั้นของการพัฒนา ตามลำดับ
1990 · IEEE 802.1D
มาตรฐานฉบับแรก ทุกอย่างที่อธิบายมาข้างบนคือฉบับนี้ ห้าสถานะ สาม timer ต้นไม้เดียวสำหรับทั้งเครือข่าย
1998 · 802.1D-1998 และ 802.1t — ตาราง cost
รายละเอียดอยู่ในหัวข้อ path cost ข้างบนแล้ว สรุปสั้น ๆ คือสูตรถูกแทนด้วยตาราง แล้วตารางถูกขยายจาก 16 บิตเป็น 32 บิต และ 802.1t ยังเป็นตัวที่แบ่ง priority 2 ไบต์ใหม่เป็น 4 บิตกับ 12 บิตอย่างที่ใช้กันอยู่ทุกวันนี้
ระหว่างทาง · สิ่งที่ผู้ผลิตแปะเข้าไปเอง
ก่อนที่ IEEE จะออกมาตรฐานเรื่องความเร็ว Cisco ทำของตัวเองไปก่อน — PortFast ให้ พอร์ตที่เสียบเครื่องข้ามช่วงรอไปเลย · UplinkFast กับ BackboneFast เร่งการสลับ ไปสายสำรอง
สามอย่างนี้สำคัญในเชิงประวัติศาสตร์เพราะแนวคิดของมันถูกดูดกลับเข้ามาตรฐานทีหลัง PortFast กลายเป็น edge port ใน 802.1w และการสลับทันทีกลายเป็นบทบาท alternate port การพัฒนาเดินทางนี้บ่อย — ของที่ขายก่อน มาตรฐานตามทีหลัง
PVST · PVST+ · Rapid PVST+ — ต้นไม้ต่อ VLAN
802.1D มีต้นไม้เดียวสำหรับทั้งเครือข่าย ซึ่งแปลว่าสายที่ถูกปิดถูกปิดสำหรับทุก VLAN พร้อมกัน ไม่มีทางให้ VLAN หนึ่งใช้เส้นซ้ายและอีก VLAN ใช้เส้นขวา
Cisco แก้ด้วยการรัน STP แยกอินสแตนซ์ต่อหนึ่ง VLAN เรียกว่า PVST ส่วน PVST+ คือ รุ่นที่ทำงานร่วมกับอุปกรณ์มาตรฐานได้ และ Rapid PVST+ คือรุ่นเดียวกันที่เปลี่ยน เครื่องยนต์ข้างในเป็น 802.1w
ได้ประโยชน์ตรงที่กระจายโหลดต่อ VLAN ได้จริง แต่ราคาที่จ่ายชัดเจนไม่แพ้กัน หนึ่ง VLAN คือหนึ่งอินสแตนซ์ที่ต้องคำนวณและต้องส่ง BPDU จำนวน VLAN เพิ่ม งานของซีพียูเพิ่มตาม อุปกรณ์แต่ละรุ่นจึงมีเพดานของตัวเอง บางแพลตฟอร์มจำกัดไว้ ที่ 256 อินสแตนซ์ บางรุ่นราว 510
นี่คือโพรโทคอลเฉพาะของผู้ผลิต ไม่ใช่มาตรฐาน IEEE และเป็นเหตุผลที่ 802.1s เกิด
2001 · 802.1w RSTP — เลิกใช้ timer เป็นเครื่องมือหลัก
เอกสารของ IEEE บรรยาย 802.1w ว่าเป็นส่วนเพิ่มของ 802.1D-1998 ที่ให้ความสามารถ ในการจัดโครงสร้างใหม่ได้อย่างรวดเร็ว ต่อมามันถูกรวมเข้าไปเป็นเนื้อเดียวกับ 802.1D-2004
ห้าสถานะยุบเหลือสาม โดยสามสถานะแรกของเดิมกลายเป็นสถานะเดียว
802.1D 802.1w in tree learns MAC
disabled ------> discarding no no
blocking ------> discarding no no
listening ------> discarding yes no
learning ------> learning yes yes
forwarding ------> forwarding yes yes
การยุบนี้ไม่ใช่แค่เรื่องชื่อ มันสะท้อนว่าเดิมมีสามสถานะที่ทำสิ่งเดียวกัน คือ ไม่ส่งและไม่จำ ต่างกันแค่เหตุผลเบื้องหลัง ซึ่งเป็นข้อมูลที่ควรอยู่ในบทบาทของ พอร์ต ไม่ใช่ในสถานะของมัน
และบทบาทคือของใหม่ที่แท้จริง 802.1w เพิ่มบทบาทที่ 802.1D ไม่มีชื่อเรียก
root พอร์ตที่ชี้ไปทาง root
designated ฝั่งที่ได้ส่งบนสายเส้นนั้น
alternate ทางสำรองไปยัง root ที่คำนวณไว้แล้ว รอเสียบแทนได้ทันที
backup ทางสำรองไปยังปลายทางเดิมบนสายเดียวกัน
ความต่างอยู่ที่คำว่าคำนวณไว้แล้ว ใน 802.1D พอร์ตที่ถูกปิดคือพอร์ตที่ไม่มี สถานะอะไรเป็นพิเศษ พอ root port ตาย ต้องเริ่มคำนวณใหม่ ใน 802.1w ตัวสำรอง ถูกจัดอันดับไว้ล่วงหน้าแล้ว การสลับจึงเป็นการเลื่อนอันดับ ไม่ใช่การคำนวณใหม่
ส่วนที่ฉลาดที่สุดคือ proposal กับ agreement เมื่อสายระหว่างสวิตช์สองตัว ขึ้นมาใหม่ ฝั่งที่ใกล้ root กว่าจะส่ง proposal ไป ฝั่งตรงข้ามจะปิดพอร์ตอื่น ของตัวเองที่ไม่ใช่ขอบเครือข่ายทั้งหมดก่อน แล้วจึงตอบ agreement กลับมา พอได้คำตอบ ฝั่งแรกก็ส่งข้อมูลได้ทันที
นี่คือการเปลี่ยนแนวคิดทั้งหมด ความปลอดภัยเดิมมาจากการรอให้นานพอจนเชื่อได้ว่า ไม่มีลูป ความปลอดภัยใหม่มาจากการที่อีกฝั่งลงมือทำให้ปลอดภัยเสร็จแล้วจึงตอบ คำตอบคือหลักฐาน ไม่ใช่การหมดเวลา
วิธีนี้ใช้ได้เฉพาะบนสายที่ต่อตรงระหว่างสองตัวเท่านั้น เพราะต้องมีคนตอบคนเดียว บนสายที่มีหลายตัวร่วมกัน RSTP ยังต้องกลับไปใช้ timer แบบเดิม
2002 · 802.1s MSTP — VLAN หลายอัน ต้นไม้ไม่กี่ต้น
IEEE บรรยายขอบเขตของ 802.1s ไว้ว่าเป็นการเพิ่มความสามารถให้บริดจ์ใช้ spanning tree ได้หลายต้น เพื่อให้ทราฟฟิกของ VLAN ต่างกันไหลไปคนละเส้นทางได้
แนวคิดคือแยกจำนวน VLAN ออกจากจำนวนต้นไม้ PVST+ ผูกสองอย่างนี้ไว้ด้วยกัน หนึ่ง VLAN หนึ่งต้นไม้ ส่วน MSTP ให้แมป VLAN กี่อันก็ได้ลงไปยัง instance เดียวกัน พันVLAN ใช้สองอินสแตนซ์ก็ได้ถ้าต้องการแค่สองเส้นทาง
งานที่ต้องคำนวณจึงขึ้นกับจำนวนเส้นทางที่ต้องการ ไม่ใช่จำนวน VLAN ที่มี
ราคาที่จ่ายคือความซับซ้อนของแนวคิดที่เพิ่มขึ้นชัดเจน
- MSTI — ต้นไม้หนึ่งต้นภายใน region คือตัวที่แมป VLAN ลงไป
- IST — instance 0 มีอยู่เสมอ รับ VLAN ที่ไม่ได้แมปไว้ที่ไหน และเป็น ตัวแทนของทั้ง region เวลาคุยกับข้างนอก
- CIST — ต้นไม้ที่พาด region ต่าง ๆ และอุปกรณ์เก่านอก region เข้าด้วยกัน
และเงื่อนไขที่พลาดกันบ่อยที่สุดคือเรื่อง region สวิตช์สองตัวจะถือว่าอยู่ region เดียวกันก็ต่อเมื่อสามอย่างนี้ตรงกันครบ
1 ชื่อ region
2 เลข revision
3 ตารางแมป VLAN ไปยัง instance
ข้อสามไม่ได้ส่งตารางทั้งใบไปเทียบ แต่ส่งค่าแฮชของตารางไปใน BPDU ของ IST แล้ว เทียบค่ากับของตัวเอง ประหยัดพื้นที่มาก แต่แลกมาด้วยข้อเสียที่ต้องรู้ — เมื่อไม่ตรงกัน คุณจะรู้แค่ว่าไม่ตรง ไม่รู้ว่าไม่ตรงตรงไหน
ผลของการไม่ตรงกันไม่ใช่ error แต่คือสวิตช์สองตัวนั้นกลายเป็นคนละ region และ มองกันผ่าน CIST เหมือนมองอุปกรณ์เก่า ต้นไม้ที่ตั้งใจออกแบบไว้ก็ไม่เกิด โดยไม่มีอะไรบอก
2011 และ 2012 · TRILL และ SPB — ความพยายามเลิกใช้ต้นไม้
TRILL คือ RFC 6325 ปี 2011 สถานะ Standards Track ผู้เขียนคนแรกคือ Radia Perlman คนเดิม
SPB คือ IEEE 802.1aq ผ่านการรับรองวันที่ 29 มีนาคม 2012 ขอบเขตของมันระบุว่า เป็นการกำหนดการบริดจ์ตามเส้นทางสั้นที่สุดสำหรับทั้งยูนิคาสต์และมัลติคาสต์
ทั้งคู่มีเป้าเดียวกัน — เลิกปิดสาย แล้วให้ทุกเส้นทำงานพร้อมกันตามเส้นทางที่สั้น ที่สุดจริง ๆ โดยเอาแนวคิดของโพรโทคอลเราต์ติงมาใช้ที่ชั้นนี้ และ TRILL เพิ่ม hop count เข้าไปในหัวของตัวเอง คืออุดรูที่เปิดหน้านี้มาตั้งแต่ต้น
ทั้งคู่ถูกนำไปใช้จริงในวงจำกัด และไม่ใช่สิ่งที่ชนะ
สิ่งที่ชนะจริง
สิ่งที่แทน STP ในดาต้าเซ็นเตอร์จริงไม่ใช่ STP รุ่นใหม่ แต่คือการเปลี่ยนโจทย์
แบบแรก มัดสายให้สวิตช์เห็นเป็นเส้นเดียว สายขึ้นสองเส้นไปสวิตช์สองตัวถูกทำ ให้ดูเหมือนเส้นเดียวในสายตาของ STP เมื่อไม่มีลูปให้เห็น ก็ไม่มีพอร์ตไหนถูกปิด และทั้งสองเส้นส่งข้อมูลพร้อมกัน
แบบที่สอง เลิกทำเลเยอร์สองข้ามสวิตช์ไปเลย ใช้เราต์ติงระหว่างสวิตช์ ซึ่ง หมายความว่าได้ TTL กลับคืนมา ได้เส้นทางหลายเส้นพร้อมกัน และได้โพรโทคอลที่ ออกแบบมาสำหรับกราฟที่มีวงตั้งแต่แรก ส่วนเลเยอร์สองที่ยังต้องมี ก็ห่อไว้ข้างใน แล้วให้ควบคุมด้วยระนาบควบคุมแทนการเรียนรู้จากทราฟฟิก
RFC 7432 ปี 2015 ซึ่งเป็นมาตรฐานของ EVPN อธิบายข้อจำกัดของวิธีเดิมไว้ว่ามีปัญหา หลายด้าน ทั้งเรื่องการต่อหลายทาง ความซ้ำซ้อน การกระจายโหลด และการใช้หลายเส้นทาง และระบุว่า EVPN ทำให้กระจายโหลดไปยังอุปกรณ์ที่ต่ออยู่หลายจุดพร้อมกันได้
แต่ STP ยังเปิดอยู่ในเครือข่ายเหล่านั้นเกือบทั้งหมด เปิดไว้เป็นตาข่ายรับ เวลาคนต่อสายผิด ไม่ใช่กลไกที่ตัดสินเส้นทาง มันเปลี่ยนจากสถาปัตยกรรมมาเป็นเบรก ฉุกเฉิน ซึ่งเป็นตำแหน่งที่มันทำได้ดีมาก
เมื่อมันโกหก
"พอร์ตที่ถูก block คือพอร์ตที่ตายแล้ว" ไม่ใช่ มันยังรับ BPDU อยู่ตลอด และ ต้องรับ เพราะการหยุดได้ยินคือสัญญาณเดียวที่บอกว่าต้องเปลี่ยนแผน พอร์ตที่ block ที่หยุดรับด้วยคือพอร์ตที่เครือข่ายมองไม่เห็นแล้ว
"ถ้า STP ทำงานอยู่ ลูปเกิดไม่ได้" ไม่จริง STP ป้องกันลูปที่มันมองเห็น กรณีที่มันมองไม่เห็นคือสายที่ส่งได้ทางเดียว — ฝั่งหนึ่งส่งออกได้แต่รับไม่ได้ ฝั่งที่รับไม่ได้จะคิดว่าไม่มีใครอยู่ตรงข้าม แล้วเปิดพอร์ตเป็น designated ทั้งที่อีกฝั่งก็ส่งอยู่ ผลคือลูปที่ STP เป็นคนเปิดให้เอง กลไกอย่าง loop guard มีไว้แก้กรณีนี้โดยเฉพาะ
"ต้นไม้ที่คำนวณเสร็จแล้วคือต้นไม้ที่ดี" ไม่เกี่ยวกัน STP รับประกันแค่ว่าไม่มี ลูป ไม่ได้รับประกันว่าเส้นทางสั้นหรือเร็ว ถ้า root ไปตกอยู่ที่สวิตช์ตัวเล็กใน ห้องประชุม ทราฟฟิกทั้งตึกจะอ้อมไปผ่านมันโดยที่ทุกอย่างรายงานว่าปกติดี
"RSTP เร็วเสมอ" เร็วบนสายที่ต่อตรงระหว่างสวิตช์สองตัว บนสายที่มีหลายตัวร่วม กันมันกลับไปใช้ timer แบบเดิม และถ้ามีอุปกรณ์ที่พูดได้แค่ 802.1D อยู่ในวง พอร์ต ที่ติดกับมันก็ถอยกลับไปเป็น 802.1D เช่นกัน
"ครึ่งหนึ่งของแบนด์วิดท์ที่หายไปคือบั๊ก" ไม่ใช่ นั่นคือการออกแบบ และรู้ตัว ตั้งแต่ปี 1985 RFC 6325 เขียนไว้ตรง ๆ ว่า spanning tree ทำงานด้วยการปิดพอร์ต จำกัดจำนวนลิงก์ที่ส่งได้ จึงสร้างคอขวดด้วยการอัดทราฟฟิกลงลิงก์ที่เลือกไว้
ความปลอดภัย — หนึ่งเฟรมก็ยึดเครือข่ายได้
STP ไม่มีการยืนยันตัวตนใด ๆ ทั้งสิ้น ไม่มีลายเซ็น ไม่มีรหัส ใครก็ตามที่ส่ง BPDU เข้ามาได้ ก็ร่วมเลือกตั้งได้
การโจมตีที่ตรงไปตรงมาที่สุดคือส่ง BPDU ที่อ้าง priority 0 เข้าไป เนื่องจากเลข น้อยกว่าชนะ ทุกสวิตช์ในวงจะยอมรับผู้บุกรุกเป็น root ทันที แล้วคำนวณต้นไม้ใหม่ ทั้งหมดโดยหันเข้าหามัน
ผลที่ได้มีสองชั้น ชั้นแรกคือเครือข่ายหยุดทำงานระหว่างคำนวณใหม่ ชั้นที่สองร้าย กว่า — ทราฟฟิกที่เคยวิ่งตรงจะถูกจัดเส้นทางใหม่ให้ผ่านตัวที่เป็น root
การป้องกันไม่ได้อยู่ในโพรโทคอล แต่อยู่ในค่าที่ตั้งบนพอร์ต
- BPDU guard — พอร์ตที่เสียบเครื่องผู้ใช้ไม่ควรได้รับ BPDU เลย ถ้าได้รับ ให้ปิดพอร์ตทันที
- root guard — พอร์ตนี้ห้ามเป็นทางไปหา root ถ้ามี BPDU ที่ดีกว่าเข้ามา ให้ปฏิเสธ ใช้กับทิศทางที่รู้ว่า root ไม่ควรอยู่ทางนั้น
ทั้งสองอย่างนี้ไม่ได้เปิดมาให้เอง ต้องตั้งเอง และเป็นสองบรรทัดที่ควรอยู่ในทุก พอร์ตที่หันหาผู้ใช้
ตัวอย่างจริงจากงานจริง
กรณีที่ 1 — ทั้งตึกช้าลงพร้อมกันในไม่กี่วินาที
ไม่ใช่ช้าลงเรื่อย ๆ แต่ปกติดีอยู่แล้วพังพร้อมกันทั้งหมด
อ่านอย่างไร อาการพร้อมกันทั้งวงคือลายเซ็นของ broadcast storm ให้ดูตัวนับ ก่อนอย่างอื่น
switch# show interfaces Gi1/0/12 counters
Port InOctets InUcastPkts InMcastPkts InBcastPkts
Gi1/0/12 4127883904 14827 9204 18442117
InBcastPkts สิบแปดล้านบนพอร์ตเดียว ขณะที่ยูนิคาสต์อยู่แค่หลักหมื่น คือสัดส่วน ที่เป็นไปไม่ได้ในเครือข่ายปกติ
จากนั้นดูว่า STP มีความเห็นอย่างไร
switch# show spanning-tree vlan 10 detail | include from|changes
Number of topology changes 2841 last change occurred 00:00:03 ago
from GigabitEthernet1/0/12
สองพันแปดร้อยครั้ง และครั้งล่าสุดสามวินาทีที่แล้ว ต้นไม้ไม่ได้นิ่งเลย พอร์ตหมายเลข 12 คือที่ที่ควรไปดูก่อน
สิ่งที่ยังไม่ได้พิสูจน์ ตัวนับนับสะสมตั้งแต่บูต และพอร์ตที่รายงานคือพอร์ต ที่ได้ยินการเปลี่ยนแปลง ไม่จำเป็นต้องเป็นพอร์ตที่ก่อ ให้ล้างตัวนับแล้ววัดใหม่ และไล่ไปทางต้นทางทีละตัว
กรณีที่ 2 — ทุกอย่างรายงานว่าปกติ แต่ช้าอย่างอธิบายไม่ได้
ไม่มี error ไม่มีสายขาด แต่ทราฟฟิกระหว่างเซิร์ฟเวอร์สองตัวที่อยู่ตู้ติดกันช้า กว่าที่ควร
อ่านอย่างไร ถามว่า root อยู่ที่ไหน
switch# show spanning-tree vlan 10 root
Root Hello Max Fwd
Vlan Root ID Cost Time Age Dly Root Port
---------- --------- ----- ----- --- --- ---------
VLAN0010 32778 19 2 20 15 Gi1/0/8
0000.5e00.53c7
สองอย่างในนี้ผิดปกติ priority 32778 แปลว่า root ยังใช้ค่าตั้งต้น คือไม่มี ใครตั้งใจให้มันเป็น root มันชนะเพราะ MAC บังเอิญน้อยกว่า และ cost 19 คือค่า ของร้อยเมกะบิต ทั้งที่แกนกลางเป็นกิกะบิตทั้งหมด
รวมสองข้อแล้วอ่านได้ว่า root ไปตกอยู่ที่สวิตช์เล็กที่ต่อด้วยสายร้อยเมกะบิต ทราฟฟิกของทั้ง VLAN จึงอ้อมไปผ่านมัน
ทางแก้ไม่ใช่การไล่ปิดพอร์ต แต่คือตั้ง priority ที่สวิตช์แกนให้ต่ำกว่าตั้งต้น เพื่อให้ root อยู่ในที่ที่ตั้งใจ
สิ่งที่ยังไม่ได้พิสูจน์ เราเห็นว่า root อยู่ผิดที่ แต่ยังไม่รู้ว่าสวิตช์ตัว นั้นถูกเสียบเข้ามาเมื่อไรและใครเสียบ ให้เทียบกับเวลาที่อาการเริ่มก่อนสรุป
กรณีที่ 3 — เสียบสายแล้วต้องรอครึ่งนาทีก่อนใช้ได้
เครื่องที่เสียบสายใหม่ขอ IP ไม่ได้ในครั้งแรก แต่พอสักพักแล้วลองใหม่ได้เอง
อ่านอย่างไร เอาเลขมาบวกกัน 15 บวก 15 เท่ากับ 30 วินาที คือเวลาที่พอร์ตอยู่ ใน listening แล้ว learning ก่อนจะส่งข้อมูลได้ DHCP ที่ส่งคำขอออกไปในช่วงนั้น ไม่ได้ถูกปฏิเสธ มันหายไปเฉย ๆ
switch# show spanning-tree interface Gi1/0/33 detail | include port
Port 33 (GigabitEthernet1/0/33) of VLAN0010 is listening
Port path cost 4, Port priority 128, Port Identifier 128.33
คำว่า listening บนพอร์ตที่เสียบคอมพิวเตอร์คือคำตอบทั้งหมด พอร์ตแบบนี้ไม่มีวัน สร้างลูป จึงไม่มีเหตุผลให้รอ ต้องประกาศให้เป็น edge port หรือเปิด PortFast
สิ่งที่ยังไม่ได้พิสูจน์ เราพิสูจน์ได้ว่าพอร์ตรอจริง แต่ยังไม่ได้พิสูจน์ว่า นั่นคือสาเหตุเดียว ให้ตั้ง edge port แล้ววัดซ้ำ ถ้ายังพลาดอยู่ ปัญหาอยู่ที่อื่น
กรณีที่ 4 — MSTP ที่ไม่ยอมเป็น region เดียวกัน
ตั้งค่า MSTP ครบทั้งสองตัวแล้ว แต่ต้นไม้ยังไม่แยกตามที่ออกแบบ
อ่านอย่างไร เทียบค่าที่ใช้ตัดสิน region ทั้งสามอย่าง
switchA# show spanning-tree mst configuration
Name [campus]
Revision 3 Instances configured 3
Digest 0xAC36177F50283CD4B83821D8AB26DE62
switchB# show spanning-tree mst configuration
Name [campus]
Revision 3 Instances configured 3
Digest 0x3C60DA3E2B1F44C79E5A20B7C8114F0D
ชื่อตรง revision ตรง แต่ digest ต่างกัน แปลว่าตารางแมป VLAN ไปยัง instance ไม่เหมือนกัน สองตัวนี้จึงเป็นคนละ region และมองกันผ่าน CIST
digest บอกแค่ว่าต่าง ไม่บอกว่าต่างตรงไหน ต้องไปเทียบตารางเองทีละบรรทัด และจุดที่ มักพลาดคือ VLAN ที่สร้างเพิ่มทีหลังแล้วแมปที่เดียวไม่ครบสองที่
สิ่งที่ยังไม่ได้พิสูจน์ digest ต่างกันยืนยันว่าตารางต่างกัน แต่ยังไม่รู้ว่า ฝั่งไหนถูก ต้องกลับไปดูเอกสารออกแบบว่าตกลงกันไว้อย่างไร ไม่ใช่ก๊อปฝั่งใดฝั่ง หนึ่งทับอีกฝั่ง
เมื่อ STP ไม่พอ — จากปากคนที่สร้างมันเอง
ข้อวิจารณ์ที่ตรงที่สุดไม่ได้มาจากคนนอก RFC 6325 ปี 2011 ซึ่ง Radia Perlman เป็น ผู้เขียนคนแรก ระบุข้อจำกัดของการบริดจ์แบบ IEEE 802.1 ไว้สี่ข้อ
หนึ่ง เสียแบนด์วิดท์ spanning tree ทำงานด้วยการปิดพอร์ต จำกัดจำนวนลิงก์ที่ ส่งได้ จึงสร้างคอขวดขึ้นมาจากการรวมทราฟฟิกลงลิงก์ที่ถูกเลือก
สอง เส้นทางไม่ใช่เส้นทางที่สั้นที่สุด แต่เป็นเส้นทางที่เหลืออยู่หลังจาก spanning tree ตัดเส้นทางซ้ำซ้อนทิ้งไปแล้ว
สาม ไม่มีตัวนับฮอป หัวอีเทอร์เน็ตไม่มีฟิลด์นับฮอปหรือ TTL ซึ่งอันตรายเมื่อ เกิดลูปชั่วคราว เช่นตอนที่ข้อความ spanning tree หายไป
สี่ VLAN แตกออกจากกันได้ เมื่อ spanning tree จัดโครงสร้างใหม่
ข้อที่สามคือสิ่งที่บทความนี้เปิดหัวไว้ ตลอดสามสิบปี STP ไม่เคยแก้ปัญหานั้น มันแค่จัดการรอบ ๆ ปัญหานั้น สิ่งที่มาทีหลัง ไม่ว่า TRILL หรือการเปลี่ยนไปใช้ เราต์ติงระหว่างสวิตช์ ล้วนเริ่มจากการเอาตัวนับฮอปกลับมาก่อนเป็นอย่างแรก
อ้างอิง
ต้นกำเนิด
- Radia Perlman, An Algorithm for Distributed Computation of a Spanning Tree in an Extended LAN, Proceedings of the ninth symposium on Data communications (SIGCOMM '85), ACM, หน้า 44 ถึง 53 dl.acm.org/doi/10.1145/319056.319004
มาตรฐาน
- IEEE 802.1D-1990 มาตรฐานฉบับแรกของ spanning tree
- 802.1w — Rapid Reconfiguration of Spanning Tree ส่วนเพิ่มของ 802.1D-1998 ต่อมารวมเข้าเป็นเนื้อเดียวกับ 802.1D-2004
- 802.1s — Multiple Spanning Trees เพิ่มความสามารถให้ VLAN ต่างกันไหลไปคนละเส้นทางได้
- 802.1aq — Shortest Path Bridging ผ่านการรับรอง 29 มีนาคม 2012
- RFC 6325 — Routing Bridges (RBridges): Base Protocol Specification กรกฎาคม 2011 Perlman และคณะ แหล่งของข้อจำกัดสี่ข้อในหัวข้อสุดท้าย
- RFC 7432 — BGP MPLS-Based Ethernet VPN กุมภาพันธ์ 2015 ข้อจำกัดของวิธีเดิมและการต่อหลายทางแบบใช้งานได้ทุกเส้น
- RFC 4188 — Definitions of Managed Objects for Bridges ช่วงค่าที่ตั้งได้ของ timer และ priority และประโยคที่บอกว่า path cost เป็นแค่ค่าที่แนะนำ
ของจริงบนเครื่อง
man ifconfigบน macOS — ค่าตั้งต้นและช่วงของmaxagefwddelayhellotimepriorityและประโยคที่บอกว่า-stpคือค่าตั้งต้นnet/bridge/br_stp_bpdu.cในเคอร์เนล Linux —buf[35]ที่ยืนยันขนาด BPDU และSTP_HZ 256ที่บอกหน่วยของฟิลด์ timernet/bridge/br_if.c— ตาราง path cost จริงที่ให้กิกะบิตเป็น 5 ไม่ใช่ 4show spanning-treeและshow spanning-tree mst configurationบนสวิตช์ สองคำสั่งที่ตอบคำถามเรื่อง STP ได้เกือบทั้งหมด
อ่านต่อในชุดนี้
- อีเทอร์เน็ต — ที่มาของเฟรมที่ไม่มีฟิลด์อายุ
- MAC address — สวิตช์ทำงานอย่างไร และทำไม broadcast ถึงไปถึงทุกเครื่องบนสายเดียวกัน
- VLAN — สิ่งที่ PVST+ และ MSTP พยายามจัดการ
- Internet Protocol — TTL ที่อีเทอร์เน็ตไม่มี