CIDR 技術:路由彙總與超網怎麼算
CIDR 技術用在路由上,就是把多個連續的網段合併成一條字首更短的路由,減少路由條目、隔離網路變化。演算法的核心是把網段寫成二進位制,取共同的字首位。能否精確彙總,取決於合起來的位址數是不是 2 的冪、起點是否對齊、中間有沒有缺口。
CIDR 技術在路由層面的用途,是把多個連續的網段合併成一條字首更短的路由,這個動作叫路由彙總,也叫路由聚合;彙總出來的那個大塊,在跨過 A、B、C 類邊界時被稱為超網。例如 192.168.32.0/24 到 192.168.39.0/24 這 8 個網段,可以彙總成一條 192.168.32.0/21。計算方法是把網段寫成二進位制,取它們從左往右完全相同的那幾位,相同位數就是彙總後的字首長度。彙總能否“精確”,也就是不多吸進不屬於你的位址,取決於三個條件:合起來的位址數是 2 的冪、起點對齊到彙總塊的大小、中間沒有缺口。下面給出演算法、例題、失敗原因和裝置上的配置方法。
路由彙總、超網、CIDR 聚合是什麼關係
這三個詞經常混用,說的是同一類操作,只是側重點不同:
| 說法 | 英文 | 側重點 | 例子 |
|---|---|---|---|
| 路由彙總 | Route Summarization | 在路由協議或路由表裡,用一條短字首代替多條長字首 | OSPF 區域邊界把 32 條 /24 彙總成一條 /19 |
| 路由聚合、CIDR 聚合 | Route Aggregation | 與彙總同義,BGP 裡的叫法,命令就叫 aggregate | 運營商把客戶的小塊聚合成自己的大字首對外宣告 |
| 超網 | Supernetting | 彙總後的字首比有類掩碼還短,跨過了 A、B、C 類邊界 | 4 個 C 類 192.168.32.0/24 至 192.168.35.0/24 合成 /22 |
區別只在超網:它強調“比有類邊界更短”。把 10.1.0.0/24 到 10.1.255.0/24 彙總成 10.1.0.0/16 是路由彙總,但 /16 仍比 A 類的 /8 長,嚴格說不叫超網;把 4 個 C 類合成 /22 才是超網。在 CIDR 普及之前,路由器按位址類別處理路由,比有類掩碼還短的字首無法表達,CIDR 允許任意字首長度,超網才成為可能。今天的裝置都按無類方式工作,這個區分主要出現在教材和考試裡,工作中說“彙總”即可。
彙總帶來的好處很具體:上游裝置的路由表變小;內部某個網段增刪或閃斷,只要彙總路由還在,上游感知不到,路由協議不會因此在全網重新計算;ACL、防火牆策略也可以按彙總塊寫一條規則。
彙總演算法:四步求出彙總路由
以 192.168.32.0/24 到 192.168.39.0/24 共 8 個網段為例:
- 找出變化的那一節。8 個網段的前兩節都是 192.168,第三節從 32 變到 39,第四節都是 0,只需要看第三節。
- 把這一節寫成二進位制。只寫最小值和最大值就夠了,中間的值一定夾在兩者之間:
32 = 0010 0000
39 = 0010 0111
^^^^ ^ 前 5 位相同,後 3 位不同
- 數相同的位數,加上前面固定的節。前兩節固定 16 位,第三節相同 5 位,彙總字首長度是 16 + 5 = 21。
- 把不同的位清零,得到起始位址。第三節保留前 5 位 00100,後 3 位清零,還是 32,彙總路由為 192.168.32.0/21,掩碼 255.255.248.0。
最後做一次核對:/21 包含 2 的 11 次方,即 2,048 個位址,也就是 8 個 /24,正好是第三節 32 到 39,和要彙總的網段一一對應,這是一個精確彙總。
如果網段大小相同,還有一個更快的判斷方法:數量 N 是 2 的冪,並且起始的那一節能被 N 整除,就能精確彙總,字首長度減少 log₂N 位。上例 N = 8,32 ÷ 8 = 4 整除,/24 減 3 位得 /21。兩個條件任一不滿足,就只能多吸進位址或拆成多條,後面的例題會遇到。
四道例題:從整齊到不整齊
例題一:字首長度不同的網段能彙總嗎? 一個機房有 10.40.8.0/23、10.40.10.0/24、10.40.11.0/25、10.40.11.128/25 四個網段。長度不同不影響演算法,把最小起點和最大終點拿出來比:最小是 10.40.8.0,最大終點是 10.40.11.255,第三節 8 = 0000 1000,11 = 0000 1011,前 6 位相同,彙總為 10.40.8.0/22。再核對位址數:512 + 256 + 128 + 128 = 1,024,與 /22 的大小相等,精確彙總。
例題二:三個網段怎麼彙總? 172.16.4.0/24、172.16.5.0/24、172.16.6.0/24。第三節 4 = 0000 0100,6 = 0000 0110,前 6 位相同,能覆蓋它們的最小字首是 172.16.4.0/22。但 /22 有 4 個 /24,多出來的 172.16.7.0/24 不屬於你。兩種處理:一是宣告兩條精確路由 172.16.4.0/23 和 172.16.6.0/24;二是宣告 /22,前提是 172.16.7.0/24 確定沒有分配給別人,並在本裝置上配丟棄路由。
例題三:數量是 2 的冪,為什麼還是不行? 172.16.6.0/24 到 172.16.9.0/24,正好 4 個。第三節 6 = 0000 0110,9 = 0000 1001,只有前 4 位相同,覆蓋它們的最小字首是 172.16.0.0/20,一口氣吸進 16 個 /24,其中 12 個不屬於你。原因是起點 6 不能被 4 整除,這 4 個網段橫跨了 172.16.4.0/22 和 172.16.8.0/22 兩個塊的邊界。精確的寫法是兩條 /23:172.16.6.0/23 和 172.16.8.0/23。
例題四:第四節上的彙總。 4 條互聯鏈路 10.255.0.0/30、10.255.0.4/30、10.255.0.8/30、10.255.0.12/30。變化發生在第四節,0 = 0000 0000,最大終點 15 = 0000 1111,前 4 位相同,24 + 4 = 28,彙總為 10.255.0.0/28。N = 4,起點 0 能被 4 整除,/30 減 2 位,結果一致。
手算容易在邊界上出錯,可以用 Python 自帶的 ipaddress 模組核對:下面的函式求出能覆蓋全部網段的最小彙總字首,並列出彙總後會多吸進哪些不屬於你的塊,列表為空就是精確彙總。
import ipaddress as ip
def summarize(nets):
nets = [ip.ip_network(n) for n in nets]
lo = min(int(n.network_address) for n in nets)
hi = max(int(n.broadcast_address) for n in nets)
plen = 32 - (lo ^ hi).bit_length() # 起點和終點相同的高位個數
sup = ip.ip_network((lo, plen), strict=False)
extra = [sup]
for n in nets: # 從彙總塊里扣掉自己的網段
out = []
for b in extra:
if b.subnet_of(n):
continue
out.extend(b.address_exclude(n) if n.subnet_of(b) else [b])
extra = out
return sup, sorted(extra)
print(summarize(["172.16.6.0/24", "172.16.7.0/24", "172.16.8.0/24", "172.16.9.0/24"]))
# 172.16.0.0/20,多吸進 172.16.0.0/22、172.16.4.0/23、172.16.10.0/23、172.16.12.0/22
print(summarize(["10.40.8.0/23", "10.40.10.0/24", "10.40.11.0/25", "10.40.11.128/25"]))
# 10.40.8.0/22,多吸進的列表為空
彙總失敗的常見原因
“彙總失敗”有兩種表現:算出來的彙總塊比實際網段大,把別人的位址也包了進來;或者彙總配上去之後,部分流量走錯、丟包。原因歸納如下:
| 原因 | 例子 | 後果 | 處理方法 |
|---|---|---|---|
| 數量不是 2 的冪 | 3 個、6 個連續 /24 | 彙總塊裡有空位 | 拆成多條精確彙總;或確認空位未分配後整塊宣告並配 Null0 |
| 起點沒對齊 | 第三節從 6 到 9 | 彙總塊成倍擴大 | 按對齊邊界拆成多條;新規劃時讓起點對齊 |
| 中間有缺口 | 8 到 15 裡有一個 /24 分給了別的機房 | 兩處都宣告覆蓋同一段的路由 | 缺口所在位置宣告更長的明細,靠最長字首匹配分流;或者回收重新規劃 |
| 網段分散在不同出口 | 10.40.8.0/23 在機房 A,10.40.10.0/23 在機房 B | 任一邊宣告 /22 都會把另一邊的流量引過來 | 各自只彙總本地擁有的部分 |
| 彙總點選錯 | 在只連了一部分網段的裝置上配彙總 | 這台裝置成為整段位址的入口,收到不屬於它的流量 | 在所有明細都匯聚到的那台裝置上彙總 |
| 彙總後的字首仍然太長 | 兩個 /26 合成 /25 後向公網宣告 | 多數運營商不接收長於 /24 的 IPv4 字首,宣告被上游過濾 | 公網宣告至少湊成 /24,具體以上游運營商的要求為準 |
第三、四行最隱蔽:兩台裝置宣告了重疊的字首,平時靠最長字首匹配各走各的,一旦某處的明細路由消失,流量就會被另一處的彙總路由吸走。所以規劃位址時,同一個彙總塊只放在一個位置,寧可多留空塊,也不要把一個塊拆給兩個機房。
彙總路由要配一條指向 Null0 的丟棄路由
彙總塊裡有未使用的位址時,必須防止環路。設想匯聚路由器 DC-R1 向核心宣告 10.40.8.0/22,自己的預設路由指向核心,而 10.40.11.0/24 還沒有啟用。一個發往 10.40.11.5 的包會這樣走:
- 核心查表,命中 10.40.8.0/22,交給 DC-R1;
- DC-R1 沒有 10.40.11.0/24 的明細,只能命中預設路由,又交回核心;
- 核心再交給 DC-R1,來回往返,直到 TTL 減到 0 才被丟棄。
TTL 為 64 的包會在這條鏈路上來回約 32 次,掃描器對整段位址做探測時,這種流量會被放大幾十倍佔用互聯頻寬。解決方法是在彙總裝置上加一條指向 Null0 的彙總路由:
ip route 10.40.8.0 255.255.252.0 Null0
Null0 是一個虛擬介面,送進去的包直接丟棄。根據最長字首匹配,10.40.8.0/23、10.40.10.0/24 這些明細路由比 /22 更長,仍然正常轉發;只有沒有明細的位址才落到這條 /22 上被丟棄,不會再回到預設路由。OSPF、EIGRP、BGP 在裝置上做彙總時,思科 IOS 預設會自動生成這條丟棄路由,靜態彙總要手工新增。
在思科、華為裝置上怎麼配彙總
彙總配置在哪裡,取決於路由從哪裡來:
! 1. 靜態宣告:本地丟棄路由 + 透過 BGP 宣告
ip route 10.40.8.0 255.255.252.0 Null0
router bgp 65001
network 10.40.8.0 mask 255.255.252.0
!
! 2. OSPF:在 ABR 上把區域 1 的明細彙總後發往骨幹區域
router ospf 1
area 1 range 10.40.8.0 255.255.252.0
!
! 3. OSPF:在 ASBR 上彙總重分佈進來的外部路由
router ospf 1
summary-address 10.40.8.0 255.255.252.0
!
! 4. EIGRP:在出介面上彙總,100 是 AS 號
interface GigabitEthernet0/0/1
ip summary-address eigrp 100 10.40.8.0 255.255.252.0
!
! 5. BGP:表中至少有一條明細時生成聚合,summary-only 抑制明細不再宣告
router bgp 65001
aggregate-address 10.40.8.0 255.255.252.0 summary-only
幾個要點:
area range只在 ABR 上、只對該區域內部的路由生效;對重分佈進來的路由要用summary-address。兩者寫錯位置時命令能輸入,但不起作用。- BGP 的
network ... mask要求路由表裡有完全一致的字首才會宣告,這也是第一種寫法要先加 Null0 靜態路由的原因。 aggregate-address不加summary-only時,彙總和明細會一起宣告出去,上游路由表並沒有變小。- 配好後用
show ip route 10.40.8.0 255.255.252.0 longer-prefixes檢視彙總路由和它下面的全部明細;OSPF、EIGRP 的彙總會顯示為is a summary ... Null0,BGP 被抑制的明細在show ip bgp裡帶有s標記。
華為 VRP 的對應寫法:
| 場景 | 思科 IOS | 華為 VRP |
|---|---|---|
| 丟棄路由 | ip route 10.40.8.0 255.255.252.0 Null0 |
ip route-static 10.40.8.0 22 NULL0 |
| OSPF 區域間彙總 | area 1 range ...(OSPF 程序下) |
abr-summary 10.40.8.0 255.255.252.0(區域檢視下) |
| OSPF 外部路由彙總 | summary-address ... |
asbr-summary 10.40.8.0 255.255.252.0(OSPF 檢視下) |
| BGP 聚合並抑制明細 | aggregate-address ... summary-only |
aggregate 10.40.8.0 22 detail-suppressed |
| 檢視結果 | show ip route ... longer-prefixes |
display ip routing-table 10.40.8.0 22 longer-match |
華為裝置做 OSPF 或 BGP 彙總時,是否自動生成指向 NULL0 的黑洞路由隨協議和軟體版本而定,配置後用 display ip routing-table 10.40.8.0 22 檢查,沒有就手工加上第一行的靜態路由。具體引數隨軟體版本略有差異,以裝置的命令手冊為準。
在 IPAM 裡怎麼落地
彙總能不能做乾淨,在分配位址的那一刻就決定了:一個 /22 只要有一個 /24 分到了別的機房,這個 /22 就再也無法完整彙總。所以位址台帳要按彙總塊來組織,而不是按“下一個空閒的 /24”來分。
Toplink DCIM 的 IP 位址管理以 CIDR 格式錄入位址段,自動算出起止位址和掩碼,大段可以自動拆分為多個 /24 分別管理;每個段記錄所屬機房、VLAN 和閘道器裝置。按機房錄入彙總塊後,哪個 /24 在哪個機房、哪些還空著一目瞭然,例題二里那種“空位到底有沒有分給別人”的問題,查一下段的歸屬就能回答。暫時不用的段可以設為鎖定,自動分配時不會被佔用,給將來的擴容和彙總留出完整的塊。
常見問題
思科的 auto-summary 是什麼,要不要關?
auto-summary 是 RIP 和 EIGRP 在有類邊界上自動彙總的功能,例如把 10.40.8.0/22 自動彙總成 10.0.0.0/8。同一個有類網路的子網分散在不同位置時,它會讓兩邊都宣告同一條 /8,造成流量走錯。EIGRP 從 IOS 15.0(1)M 起預設關閉;RIPv2 在不少 IOS 版本里預設開啟,用 show ip protocols 可以確認當前狀態。今天的網路應當執行 no auto-summary 關閉它,改為手工彙總。
IPv6 也能這樣彙總嗎?
能,演算法相同,只是按十六進位制換算二進位制。例如 2001:db8:10::/48 到 2001:db8:13::/48 四個塊,第三組 0x10 到 0x13 的前 14 位相同,加上前兩組的 32 位,彙總為 2001:db8:10::/46。IPv6 位址空間大,規劃時按 2 的冪對齊預留,彙總通常比 IPv4 簡單。
彙總後某個子網斷了,上游還會把流量送過來嗎?
會。只要彙總範圍內還有任何一個明細路由存在,彙總路由就一直宣告,上游看不到明細的變化,發往斷開子網的流量仍會送到彙總裝置,再被 Null0 丟棄。這是彙總隔離故障的代價:需要靠監控發現明細路由的消失,而不是靠上游路由表。