Con switch không thông minh: nó học cả mạng LAN chỉ bằng cách nghe ai vừa nói
Switch Ethernet mù tịt với IP, chỉ có một phản xạ: nhớ source MAC. Cách switch học, flood và lọc frame, và vì sao mẹo đó vừa hay cũng vừa là lỗ hổng.
"Thầy ơi, làm sao con switch biết máy bạn em đang ở cổng số mấy để mà gửi qua?"
"Good Question bạn nhỏ ạ, switch nó thông minh, nó học MAC address."
Câu đó mình nói cả trăm lần rồi. Nhưng nếu em ấy hỏi tiếp "học bằng cách nào?", thì câu trả lời sẽ lòi ra là "cũng không được thông minh lắm đâu"
Sự thật là: lúc con switch vừa cắm điện, nó không biết gì hết. Bảng MAC address rỗng tinh. Nó không biết máy nào ở cổng nào, không biết trên mạng có bao nhiêu thiết bị, không biết cả việc có tồn tại một cái máy tên là "laptop của bạn em" hay không. Vậy mà chỉ trong vài giây sau khi mọi người bắt đầu gõ phím, nó dựng được bản đồ toàn bộ cái LAN trong phòng. Bằng cách nào?
Bằng một mẹo ngớ ngẩn đến mức mình thấy ngại khi gọi nó là "thông minh".
Đây là luận điểm của bài này, và mình tin nó khá chắc: con switch không thông minh. Nó mù tịt với nội dung gói tin, và nó chỉ có đúng một phản xạ - nhớ xem địa chỉ người gửi vừa đến từ cổng nào. Toàn bộ những hành vi mà ta gán cho sự "thông minh" của switch - học, chuyển đúng cổng, flood khi bí, lọc bỏ frame thừa - đều mọc ra từ một phản xạ duy nhất đó. Và điều mình thấy đẹp nhất, cũng là điều mình muốn kể trong bài này, là: chính vì nó đủ ngu nên nó mới nhanh được tới vậy. Còn chính vì nó ngây thơ tin mọi địa chỉ người gửi, nên nó mới dễ bị lừa tới vậy.
Mình kể chuyện con switch, nhưng thứ mình thật sự muốn bàn nằm sâu hơn một tầng: rằng lượng trí thông minh đúng cho một công việc thường là lượng tối thiểu đủ chạy, và một hệ thống để hành vi phức tạp tự mọc ra từ một luật nhỏ gần như luôn thắng một hệ thống được nhồi sẵn sự khôn ngoan. Switch chỉ là ví dụ gọn nhất mình biết. Nhưng nó là một ví dụ mà cái thời "nhồi AI vào mọi thứ" của chúng ta đang quên rất nhanh - nên mình muốn để cuối bài quay lại chỗ này.
Để thấy được điều đó, mình phải đào xuống từng lớp. Bắt đầu từ cái mà switch thực sự nhìn thấy.
Cái phong bì: switch đọc gì trên một Ethernet frame?
Trước khi nói switch "học" cái gì, phải biết nó nhìn thấy cái gì đã. Và đây là chỗ làm mình thích Ethernet: con switch nhìn một frame giống hệt cách người đưa thư nhìn một cái phong bì. Nó đọc địa chỉ ngoài bì. Nó không bao giờ bóc thư ra đọc.
Một Ethernet frame, khi trải phẳng ra, chỉ là một chuỗi byte có cấu trúc cố định [1]:

- Preamble + SFD (8 byte): một chuỗi
1010...để đồng bộ đồng hồ giữa hai bên, kết thúc bằng Start Frame Delimiter báo "hết rao đầu, frame thật bắt đầu từ đây". Cái này thậm chí không được tính vào kích thước frame. Nó là tiếng hắng giọng trước khi nói. - Destination MAC (6 byte): gửi cho ai.
- Source MAC (6 byte): ai gửi.
- Type/Length (2 byte): ruột bên trong là protocol gì.
0x0800là IPv4,0x0806là ARP,0x86DDlà IPv6 [2]. - Data (46 - 1500 byte): nội dung thật, thường là một IP packet.
- FCS (4 byte): một con số checksum để bên nhận biết frame có bị hỏng dọc đường không.
Bây giờ là điểm mấu chốt mà giáo trình hay lướt qua. Trong sáu trường này, con switch Layer 2 chỉ thực sự quan tâm đến hai trường: Destination MAC (để biết gửi đi đâu) và Source MAC (để học). Cái trường Type/Length kia, cái nói cho bạn biết bên trong là IPv4 hay IPv6 ấy? Switch không thèm đọc. Nó không biết, không cần biết, và không quan tâm bên trong frame là một request HTTP, một câu lệnh SQL, hay một con virus. Với nó, phần Data chỉ là "đồ trong bì", và việc của người đưa thư không phải là đọc thư.
Đây không phải hạn chế. Đây là thiết kế. Một con switch không phải bóc gói, không phải hiểu IP, không phải chạy logic định tuyến - đó là lý do nó có thể chuyển hàng triệu frame mỗi giây trong khi một con router (phải đọc tới Layer 3) thì chậm hơn hẳn ở cùng tầm giá. Switch nhanh vì nó lười đọc.
Hai con số fossil: FCS và cái mốc 64 byte
Có hai chi tiết trong frame đáng dừng lại, vì chúng kể một câu chuyện về lịch sử.
Cái thứ nhất là FCS. Bên gửi chạy một phép tính CRC-32 trên toàn bộ frame rồi nhét kết quả vào 4 byte cuối. Bên nhận tính lại y hệt. Khớp thì frame sạch, lệch một bit thôi cũng đủ để frame bị vứt. Để ý: FCS chỉ phát hiện lỗi, không sửa được lỗi. Ethernet chọn triết lý "nghi ngờ thì vứt, để tầng trên lo gửi lại" thay vì cố vá. Đơn giản, và đơn giản thì nhanh.
Cái thứ hai thú vị hơn nhiều: frame tối thiểu phải là 64 byte. Frame nào ngắn hơn bị coi là "runt" và bị quẳng đi không thương tiếc. Giáo trình nói vậy rồi dừng. Nhưng tại sao lại là 64? Tại sao không phải 32, không phải 40?
Câu trả lời là một hóa thạch từ những năm 1980, khi Ethernet còn chạy trên một sợi cáp đồng trục dài mà tất cả máy tính cắm chung vào, và ai cũng có thể nói cùng lúc gây ra collision. Để phát hiện collision, có một luật vật lý nghiệt ngã: một máy phải vẫn còn đang phát vào đúng lúc tín hiệu va chạm từ đầu xa nhất của mạng dội ngược về tới nó. Nếu nó phát xong quá sớm, collision xảy ra mà nó không hề hay biết. Người ta tính ra với đường kính mạng tối đa khoảng 2500 mét, thời gian đi-và-về đó là 512 bit times. Tức là mọi frame phải dài ít nhất 512 bit, hay 64 byte, để máy gửi còn "ngậm" trên đường dây đủ lâu mà nghe được tiếng va chạm [3].
Nếu một gói tin thật sự nhỏ hơn 64 byte (ví dụ một ACK bé tí), Ethernet nhét thêm các byte rác gọi là pad vào trường Data cho đủ 64. Phí phạm? Đúng. Nhưng cần thiết, vào năm 1983.
Đây là chỗ mình thấy mỉa mai một cách đáng yêu. Cái mạng trong phòng lab của mình hôm nay là switched Ethernet full-duplex. Mỗi máy có một đường riêng tới switch, gửi và nhận cùng lúc, collision về mặt vật lý không thể xảy ra nữa. Cái lý do duy nhất để có mốc 64 byte đã chết từ lâu. Vậy mà mọi card mạng trên đời, ngay lúc này, vẫn ngoan ngoãn pad frame cho đủ 64 byte. Chúng ta vẫn đang giải một bài toán đã không còn tồn tại, chỉ vì gỡ nó ra thì phá vỡ tương thích ngược. Cả ngành công nghệ đầy những hóa thạch như vậy, và mình nghĩ biết nhìn ra chúng là một phần của việc hiểu sâu.
Cái tên trên phong bì: MAC address là gì, và vì sao "burned-in" là một lời nói dối
Switch đọc địa chỉ trên bì. Vậy cái địa chỉ đó trông thế nào?
Một MAC address là 48 bit, viết thành 12 chữ số hexa cho gọn mắt, ví dụ 00-60-2F-3A-07-BC. Nhưng 48 bit đó không phải một khối liền. Nó chia làm hai nửa, và mỗi nửa kể một chuyện khác nhau:

- 24 bit đầu (3 byte) là OUI - Organizationally Unique Identifier. Đây là mã mà nhà sản xuất phải mua từ IEEE Registration Authority [4]. Cisco có OUI
00-60-2F. Cứ nhìn 3 byte đầu của một MAC là đoán được hãng nào làm ra cái card đó. - 24 bit sau do vendor tự gán, đảm bảo không trùng trong nội bộ hãng.
IEEE quản nửa đầu, vendor quản nửa sau, nên về lý thuyết mỗi MAC là duy nhất trên hành tinh. Nghe rất chắc chắn. Và đây là chỗ giáo trình bắt đầu nói dối bạn.
Giáo trình gọi MAC là "burned-in address", địa chỉ được khắc cứng vào ROM của card mạng, không đổi được. Nghe rất chắc chắn. Nhưng đó là một lời nói dối tử tế. Trên mọi hệ điều hành hiện đại, bạn đổi MAC address bằng một dòng lệnh trong vài giây. Bí mật nằm ở một bit: bit thấp thứ hai của byte đầu tiên là U/L bit. Khi nó bằng 1, địa chỉ là "locally administered", tức là do phần mềm đặt chứ không phải OUI thật [5]. Đây chính xác là cái mà mọi công cụ MAC spoofing bật lên.
Hệ quả thực tế thì không tử tế chút nào: nếu bạn đang bảo vệ mạng bằng cách lọc theo MAC address (chỉ cho phép các MAC "đã biết" vào mạng), thì lớp bảo vệ đó mỏng như giấy. Kẻ tấn công chỉ cần ip link set dev eth0 address rồi đội lốt một MAC hợp lệ. Cùng cái sự ngây thơ này, khi đẩy lên một bậc, là gốc rễ của ARP poisoning từ tầng Data Link, nên ở đây mình chỉ ghim lại một câu: MAC không phải danh tính, nó chỉ là một cái nhãn dán, và nhãn thì bóc dán lại được.
Một chi tiết nhỏ mà mình thấy đẹp: vì sao multicast luôn bắt đầu bằng 01 hoặc 33
Còn một bit nữa đáng nói, vì nó giải thích một điều mà giáo trình bắt học thuộc lòng mà không nói lý do. Bạn được dạy: MAC broadcast là FF-FF-FF-FF-FF-FF, MAC multicast cho IPv4 bắt đầu bằng 01-00-5E, cho IPv6 thì 33-33. Học thuộc đi. Nhưng tại sao là những con số đó?
Vì bit thấp nhất của byte đầu tiên là I/G bit (Individual/Group). Bằng 0 nghĩa là unicast (gửi cho một máy), bằng 1 nghĩa là group, tức multicast hoặc broadcast. Thử nhìn lại: 0x01 là 00000001, bit cuối là 1. 0x33 là 00110011, bit cuối là 1. 0xFF là 11111111, bit cuối là 1. Cả ba đều là group address, và byte đầu của chúng luôn là số lẻ. Trong khi MAC unicast của bạn, byte đầu luôn chẵn. Khi card mạng nhìn đúng một bit đó, nó biết ngay frame này gửi riêng cho mình hay gửi cho cả đám. Một bit, một quyết định. Mình thích những thiết kế mà mọi con số tưởng như tùy tiện hóa ra đều có lý do gọn gàng nằm dưới.
Cái mẹo duy nhất: switch học bằng cách nghe địa chỉ người gửi
Bây giờ mới tới phần làm mình khựng lại trước câu hỏi của sinh viên. Quay lại con switch vừa cắm điện, bảng MAC rỗng tinh. Nó học cả cái LAN bằng cách nào?
Bằng đúng một quy tắc, và mình muốn bạn đọc chậm câu này: mỗi khi một frame đi vào, switch nhìn Source MAC của frame đó và ghi nhớ "à, cái địa chỉ này vừa nói chuyện ở cổng số N". Hết. Đó là toàn bộ cơ chế học.

PC-A gửi một frame, frame đó đi vào cổng 1 của switch. Switch nhìn Source MAC là 00-0A, và lập tức viết vào bảng: cổng 1 ứng với 00-0A. Nó không cần ai khai báo, không cần cấu hình, không cần hỏi han. Nó chỉ nghe lén địa chỉ người gửi trên những lá thư mà đằng nào nó cũng phải chuyển. Việc học là một tác dụng phụ của việc nghe.
Để ý sự tinh tế ở đây. Switch học từ Source MAC, không phải Destination. Nó học về nơi một thiết bị đang ở bằng cách nghe thiết bị đó nói, chứ không phải bằng cách nghe ai đó gọi nó. Cũng giống như trong một căn phòng tối, bạn không biết người ta đứng đâu cho tới khi họ cất tiếng. Ai im lặng thì với switch, người đó không tồn tại. Và nếu một entry không "nói" lại gì trong 300 giây, switch mặc định quên nó đi [6]. Bộ nhớ của switch là một bộ nhớ của sự lãng quên có chủ đích: chỉ nhớ những ai vừa mới lên tiếng.
Vậy khi switch chưa biết gửi đi đâu thì sao? Nó hét lên.
Học là một chuyện. Nhưng ngay giây phút PC-A gửi frame đầu tiên cho PC-D, switch lâm vào thế bí: nó vừa học được PC-A ở cổng 1, nhưng nó chưa hề biết PC-D ở đâu, vì PC-D chưa nói câu nào. Bảng MAC không có dòng nào cho 00-0D. Switch phải làm gì với cái frame này?
Câu trả lời, và đây là chỗ mình thấy con switch thành thật một cách đáng yêu: nó flood. Nó gửi frame ra tất cả các cổng, trừ cổng mà frame vừa đi vào. Nói cách khác, khi switch không biết người nhận ở đâu, nó không vứt frame đi, cũng không đoán bừa. Nó hét vào cả phòng: "Có ai là 00-0D không? Thư cho bạn đây!" Hành vi này có tên kỹ thuật là unknown unicast flooding.

PC-D nhận được frame, thấy đúng địa chỉ mình, xử lý. Còn PC-B và PC-C cũng nhận được, nhìn Destination MAC, thấy "không phải mình", lặng lẽ vứt đi. Phí một chút băng thông, nhưng frame đến đúng đích.
Mà đây mới là phần hay: ngay khi PC-D trả lời PC-A, frame phản hồi đó đi vào switch mang theo Source MAC 00-0D. Và thế là switch học luôn: cổng 4 ứng với 00-0D. Từ giây phút đó trở đi, mọi frame gửi cho PC-D không còn bị flood nữa, nó được gửi thẳng ra đúng cổng 4. Hành vi này gọi là filtering: bảng đã có đích thì chỉ gửi một cổng, không làm phiền ai khác.
Bạn thấy vòng lặp đẹp chưa? Switch bắt đầu từ ngu dốt hoàn toàn. Mỗi lần nó buộc phải hét lên vì không biết, thì chính câu trả lời cho tiếng hét đó lại dạy nó thêm một entry. Càng chạy, nó càng ít phải hét, càng filter chính xác. Nó tự dạy mình từ chính cái dòng traffic mà nó đang phục vụ, không cần một bộ não trung tâm nào cả. Toàn bộ "trí thông minh" của switch chỉ là: nhớ source, tra destination, không thấy thì hét. Ba mệnh đề. Đó là tất cả.
Broadcast (FF-FF...) và multicast cũng được flood y như unknown unicast, vì bản chất chúng là "gửi cho cả đám". Đó là lý do một mạng quá nhiều broadcast sẽ nghẽn: mỗi gói broadcast là một lần switch hét vào mọi cổng.
Nhanh hay chắc? Hai cách switch quyết định chuyển frame
Có một câu hỏi nữa mà switch phải trả lời, và nó là một đánh đổi kinh điển trong kỹ thuật: khi một frame đang chảy vào, switch nên đợi đọc hết rồi mới chuyển, hay chuyển ngay khi vừa đủ thông tin?

Store-and-forward: switch đợi nhận trọn vẹn cả frame, tính CRC để kiểm tra FCS, và chỉ khi frame sạch mới tra bảng và chuyển đi. Frame lỗi bị vứt ngay tại switch, không lan ra mạng. Đổi lại, mỗi frame phải nằm chờ trong switch cho tới byte cuối. Chậm hơn, nhưng sạch hơn. Đây cũng là chế độ bắt buộc nếu bạn muốn làm QoS, vì muốn ưu tiên gói VoIP hơn gói tải web thì phải đọc xong frame mới phân loại được.
Cut-through: switch chỉ đợi đọc đúng 6 byte Destination MAC (nằm ngay sau preamble), tra bảng, rồi bắn frame đi ngay trong khi phần đuôi của frame còn chưa chảy vào hết. Nhanh hơn rõ rệt. Nhưng có một cái giá: switch chuyển frame trước cả khi đọc tới FCS, nên nó không biết frame có lỗi hay không. Nếu frame hỏng, nó vẫn vô tư chuyển đi, để card mạng đầu kia tự phát hiện và vứt. Cut-through đánh cược rằng lỗi hiếm, và đổi sự chắc chắn lấy độ trễ thấp.
Cut-through có hai biến thể, và một trong số đó kéo cái con số 64 quay lại ám chúng ta lần nữa. Fast-forward bắn đi ngay sau khi đọc địa chỉ đích, độ trễ thấp nhất. Fragment-free thì đợi đọc đủ 64 byte đầu rồi mới bắn, vì hầu hết lỗi và collision xảy ra trong 64 byte đầu của frame. Lại là 64. Cái slot time của năm 1983 vẫn còn lảng vảng trong logic của switch năm 2026, lần này hóa trang thành một bộ lọc lỗi cho cut-through. Fragment-free là một thỏa hiệp: chắc hơn fast-forward, nhanh hơn store-and-forward.
Không có lựa chọn nào "đúng" tuyệt đối. Datacenter chạy ứng dụng nhạy độ trễ thì thích cut-through. Mạng cần độ sạch và QoS thì chọn store-and-forward. Đây là kiểu đánh đổi mà mình muốn sinh viên nhìn ra, vì nó lặp lại ở khắp nơi trong kỹ thuật: bạn gần như luôn phải chọn giữa nhanh và chắc, và "tùy hoàn cảnh" không phải câu trả lời lười biếng, nó là câu trả lời đúng.
Một cái bẫy thật ngoài đời: duplex mismatch
Để mình kể một thứ không nằm gọn trong lý thuyết nhưng cắn người ta đau nhất ngoài thực tế.
Mỗi cổng switch có hai thiết lập cơ bản: tốc độ (10/100/1000 Mbps) và duplex (full hay half). Đây thực ra là chuyện của tầng vật lý (Layer 1), nhưng nó cắn vào hành vi switching ngay lập tức nên mình kể luôn ở đây. Full-duplex là cả hai đầu nói và nghe cùng lúc. Half-duplex là mỗi lúc chỉ một đầu được nói. Thường thì hai thiết bị tự thương lượng với nhau qua autonegotiation để chọn cấu hình tốt nhất cả hai cùng hỗ trợ.
Vấn đề xảy ra khi một đầu bật autonegotiation còn đầu kia bị ai đó cấu hình cứng. Đầu autoneg không tìm được bạn nhảy, nó lùi về mặc định half-duplex. Đầu kia thì đang full-duplex. Và thế là:

Đầu full-duplex tin rằng nó được phát bất cứ lúc nào, nên nó phát thoải mái. Đầu half-duplex thì tin rằng chỉ được phát khi đường rảnh, và mỗi lần đầu kia phát chen vào lúc nó đang phát, nó ghi nhận đó là collision, rồi backoff, rồi phát lại. Kết quả: đường link vẫn "up", ping vẫn thông, nhưng throughput tụt thê thảm và bạn thấy một đống late collision trong log. Cái độc ác là không bên nào sai cả. Mỗi bên đều hành xử hoàn hảo đúng theo cấu hình của riêng nó. Lỗi nằm ở chỗ hai cái "đúng" đó không khớp nhau. Mình đã mất nguyên một buổi chiều thời còn đi làm để truy ra một sự cố "mạng chậm bất thường" mà thủ phạm chỉ là một bên ai đó gõ speed 100 duplex full còn bên kia để auto.
Bài học mình rút ra và vẫn dặn sinh viên: hoặc bật autoneg cả hai đầu, hoặc tắt cả hai đầu và cấu hình tay khớp nhau. Đừng để một đầu auto một đầu cứng. Và may là phần lớn phiền toái về cáp thẳng/chéo ngày nay đã được auto-MDIX lo, switch tự phát hiện loại cáp và đảo chân cho đúng, nên ta không còn phải nhớ "switch nối switch dùng cáp chéo" nữa. Nhưng duplex mismatch thì auto-MDIX không cứu được, nó vẫn rình ở đó.
Cái ngu của switch vừa là sức mạnh, vừa là lỗ hổng
Tới đây mình muốn dừng lại và quay về câu hỏi của em sinh viên, vì giờ mình có thể trả lời thành thật.
Switch không thông minh. Nó học cả cái LAN chỉ bằng cách nghe lén địa chỉ người gửi trên những frame nó đằng nào cũng phải chuyển, lưu vào một cái bảng, và khi bí thì hét vào mọi cổng. Chính vì nó không cố hiểu nội dung, không đụng tới Layer 3, không chạy logic phức tạp, mà nó mới nhanh được. Cái ngu là một lựa chọn thiết kế, và nó là một lựa chọn xuất sắc.
Nhưng mọi sức mạnh đến từ một giả định, và giả định nào cũng có thể bị bẻ. Switch tin vô điều kiện vào Source MAC của mọi frame. Nó không bao giờ hỏi "địa chỉ người gửi này có thật không?". Cái sự tin người đó, cộng với một sự thật phũ phàng là bảng MAC có dung lượng hữu hạn (Catalyst 2960 chỉ chứa được 8192 entry [7]), dẫn thẳng tới một đòn tấn công kinh điển.
Hình dung thế này. Có một người gác cổng giữ cuốn sổ ghi "ai ở phòng nào", và ông ấy tin tuyệt đối mọi cái tên người ta tự xưng. Bạn xông vào, hét tên 8192 cái tên giả với 8192 địa chỉ giả, cuốn sổ đầy ự. Giờ có khách thật tới, ông gác cổng hết chỗ ghi, đâm hoảng, và để khỏi làm mất thư, ông ấy chuyển sang chế độ "đọc to mọi lá thư cho cả tòa nhà nghe".
Đó chính xác là MAC flooding. Kẻ tấn công dùng tool như macof bơm hàng nghìn frame mỗi giây với Source MAC ngẫu nhiên. Bảng MAC 8192 entry đầy trong vài giây. Switch không còn chỗ học entry hợp lệ, nên với mọi frame nó đều rơi vào trạng thái "unknown unicast" và buộc phải flood [8]. Switch thoái hóa thành một cái hub: mọi frame của mọi người bị flood ra mọi cổng. Kẻ tấn công cắm Wireshark vào và nghe lén toàn bộ traffic của cả LAN. Cùng một cơ chế flood làm switch chạy được khi nó ngu dốt lúc khởi động, cũng là cơ chế biến nó thành máy nghe lén khi bị ép ngu dốt trở lại.
Đây là chỗ mình thấy rõ nhất cái ý: lỗ hổng không phải một con bug mà ai đó quên fix. Lỗ hổng chính là tính năng, nhìn từ một góc khác. Cơ chế học-rồi-flood không "sai", nó chỉ được thiết kế cho một thế giới mà mọi thiết bị trong LAN đều đáng tin. Cái thế giới đó chưa bao giờ thật sự tồn tại. Nếu bạn muốn xem đòn này chạy thật ra sao và người ta vá nó thế nào, mình đã đào sâu trong bài về MAC flooding attack.
Vậy thì
Mình quay lại lớp tuần sau, và lần này khi tới slide "switch học MAC address", mình không nói "switch nó thông minh" nữa. Mình nói: "Con switch này ngu lắm. Nó không hiểu một chữ nào trong gói tin của các em. Nó chỉ làm đúng một việc, và từ đúng một việc đó, mọi thứ còn lại tự mọc ra." Mấy em nhìn mình hơi lạ. Nhưng mình tin đó là cách hiểu trung thực hơn, và lạ thay, cũng dễ nhớ hơn cái từ "thông minh" mơ hồ kia.
Giờ thì mình quay lại cái ý đã hứa ở đầu bài, và lần này nói thẳng quan điểm chứ không úp mở: switch nhanh và đáng tin không phải dù nó ngu, mà chính vì nó ngu. Cái mẹo "nhớ source, tra destination, bí thì hét" tầm thường đến mức buồn cười, nhưng chính sự tầm thường đó cho nó ba thứ mà một thiết kế khôn ngoan hơn sẽ đánh mất: nó chạy được ở wire speed vì mỗi quyết định chỉ là một lần tra bảng, nó debug được bằng đúng một câu show mac address-table, và khi hỏng thì hỏng theo kiểu đoán trước được. Mình tin lượng trí thông minh đúng cho một công việc thường là lượng tối thiểu đủ chạy, và một hệ thống để hành vi phức tạp tự mọc ra từ một luật nhỏ gần như luôn bền hơn, nhanh hơn, dễ sửa hơn một hệ thống được nhồi sẵn sự khôn. Đó là một niềm tin mình sẵn sàng chịu trách nhiệm, không phải một câu vibe để kết bài cho đẹp.
Tất nhiên sẽ có người cãi: "Đó là chuyện của quá khứ. Tương lai là switch thông minh: Layer 3 switch, SDN, programmable switch P4 lập trình được từng hành vi. Cái dumbness mày đang ca ngợi sắp bị thay thế."
Mình đã tin đúng câu này mấy năm, hồi SDN còn là buzzword nóng nhất phòng họp. Nhưng nhìn kỹ vào chính mấy con switch "thông minh" đó, cái dumbness chưa hề bị thay - nó chỉ bị đẩy xuống và giữ nguyên một cách rất cẩn thận. Ngay trong một con Broadcom Tomahawk chuyển hàng chục Tbps, hay một con Tofino lập trình được bằng P4, cái fast path xử lý từng packet vẫn là silicon fixed-function ngu đặc, làm đúng vài luật match-action. Cái "thông minh" - routing protocol, policy, SDN controller - sống ở control plane chạy chậm hơn nhiều bậc, và nó không bao giờ được phép chạm vào đường đi của từng gói. P4 không cho bạn nhét trí khôn vào fast path, nó chỉ cho bạn sắp xếp lại các luật ngu linh hoạt hơn. Lý do thì vẫn y nguyên từ 1983: mỗi lần bạn thêm một quyết định vào con đường mà mọi packet phải đi qua, bạn trả giá bằng latency, bằng một failure mode mới, bằng một thứ khó truy lúc 2 giờ sáng. Người ta không làm chỗ nóng thông minh hơn. Người ta cố giữ nó ngu nhất có thể.
Có một ý mình vẫn còn ngồi với. Con switch là một sinh vật học về thế giới hoàn toàn bằng cách nghe xem ai vừa cất tiếng, mà không bao giờ cần hiểu họ nói gì. Nó là một lời nhắc rằng đôi khi thiết kế giỏi nhất không phải thêm cho hệ thống một bộ não, mà là tìm ra cái luật đủ nhỏ để bộ não trở thành thừa. Mình không chắc nguyên lý đó đúng tới đâu ngoài phạm vi mạng, và mình sẽ không giả vờ là chắc. Nhưng mỗi lần thấy một sản phẩm gắn chữ "AI-powered" vào một việc mà một câu if-else làm xong trong 1ms, mình lại nghĩ tới con switch.
Nếu bạn đang học CCNA và tới đúng Module 7 này [9], mình mong bạn đừng học thuộc lòng "switch học source MAC, flood unknown unicast" như một câu kinh. Hãy hỏi tại sao mỗi mệnh đề tồn tại, và bạn sẽ thấy chúng nối vào nhau gọn đến bất ngờ. Còn nếu bạn nghĩ mình đang lãng mạn hóa một con chip chuyển frame, hoặc tin rằng tương lai thuộc về switch càng-ngày-càng-thông-minh, mình rất muốn nghe bạn cãi lại.
Bình
[1]
IEEE Std 802.3-2022 - IEEE Standard for Ethernet, IEEE Standards Association, 2022 - Chuẩn Ethernet chính thức. Định nghĩa slot time = 512 bit times cho 10/100 Mbps, frame format, và FCS dùng CRC-32.
[2]
Charles Hornig, "RFC 894: A Standard for the Transmission of IP Datagrams over Ethernet Networks", IETF, 1984-04 - Định nghĩa EtherType 0x0800 cho IPv4. Trường Type/Length báo host biết ruột frame là protocol gì, nhưng switch Layer 2 không dùng tới nó.
[3]
"Minimum Frame Size", ScienceDirect Topics, Elsevier - Giải thích vì sao 512 bit slot time dẫn tới 64 byte min frame: thời gian round-trip tín hiệu trên đường kính mạng ~2500m để station kịp phát hiện collision trước khi phát xong.
[4]
IEEE Registration Authority FAQs (OUI / MA-L), IEEE Standards Association - OUI là 24-bit (3 byte đầu của MAC). Vendor mua từ IEEE RA qua block MA-L, đảm bảo 24 bit đầu unique toàn cầu.
[5]
"MAC address", Wikipedia - Bit thấp nhất của byte đầu là I/G bit: 0 = unicast, 1 = group/multicast. Bit kế là U/L bit: 1 = locally administered, tức MAC đổi bằng software.
[6]
"mac-address-table aging-time", Cisco Command Reference, Cisco Systems - Default aging time = 300 giây (5 phút). Entry không thấy traffic trong 300s bị xoá khỏi MAC table.
[7]
"Catalyst 2960 and 2960-S Switches Software Configuration Guide", Cisco Systems - Spec chính thức Catalyst 2960: MAC address table 8192 entries. Con số hữu hạn này là lý do MAC flooding hoạt động.
[8]
"MAC flooding", Wikipedia - Khi CAM table đầy, switch fail-open: flood mọi frame ra mọi cổng như hub. Tool macof từ dsniff suite.
[9]
CCNA: Introduction to Networks v7 - Module 7: Ethernet Switching, Cisco Networking Academy - Giáo trình gốc của bài. Module 7 phủ Ethernet frame, MAC address, MAC address table, và forwarding methods.