简介:面向备考华为HCIP-Datacom(H12-831)认证的考生,这份2024年数通新题库以PDF形式整理,重点解决考试题目变动后旧资料覆盖不足、复习方向不清的问题。压缩包仅含1个PDF文件,大小约327KB,轻量便于在电脑或移动设备上随时查阅。内容围绕OSPF邻居主从关系、OSPFv3接口通告、BGP路由策略与Update属性、端口隔离、IS-IS链路限制及进程隔离、filter-policy过滤对象、IS-IS引入OSPF默认开销、链路聚合与堆叠可靠性、RSTP TC-BPDU、ACL与MQC等考点,以判断题和选择题配合答案解析呈现,便于对照错题回查概念。已有902人学习,适合需要快速梳理831高频知识点、检验掌握程度并调整备考计划的考生使用。
1. 题库的错题率为什么集中在「一个词」上
2024 数通 H12-831 题库里最让人头疼的不是多选题,而是判断题。一道题只改一个词——「所有」换成「部分」、「默认 100」换成「默认 0」、「只能」换成「可以」——答案就从 A 换成 B。很多人把这类失分归因于「背得不够」,但在教育考试的语境里,题库真正的价值不是提供标准答案,而是迫使人把每个结论背后的作用点和边界重新问一遍:这条命令在哪一层生效,这个字段缺席会不会直接断连,这个机制在哪种链路上根本不成立。搞懂这三件事,同一份题库的复习效率远高于刷三遍;搞不懂,换一版新题库照样翻车。下面从几个最典型的机制开始拆。
2. OSPF 主从选举:Router ID 大的一方凭什么拿走序列号控制权
2.1 ExStart 状态里的 MS-bit:一次比较定胜负
邻居从 2-Way 走到 ExStart,双方都会发 DD 报文,而且都把 MS 位置 1,都宣称自己是 Master。此时两个 DD 报文里的 DD Sequence Number 是各自随机生成的,两者之间没有任何关系。设备收到对端的 DD 后,拿报文里携带的 Router ID 和自己的比,大的一方胜出成为 Master,之后才开始正式交换 LSDB 摘要。
这里有两个容易记错的细节。第一,比的是 DD 报文里的 Router ID 字段,不是接口 IP、不是链路开销、更不是字符串字典序,而是按无符号 32 位整数比较。第二,Router ID 相等时没有「平局」处理方案,双方都会认为对方应该让步,邻居会卡在 ExStart 反复重传 DD,最终超时。现场遇到「邻居一直在 ExStart 转圈」,第一件事就该去看两端的 Router ID 是不是配成了同一个值。
这套判定逻辑短到可以几行写完,但正是这几行决定了后面所有序列号行为:
def negotiate_master(local_rid: int, remote_rid: int) -> bool: """ 模拟 ExStart 阶段的主从判定。 Router ID 按无符号 32 位整数比较,返回 True 表示本端成为 Master。 """ if local_rid > remote_rid: return True # 本端大,抢到 Master,掌握序列号递增权 if local_rid < remote_rid: return False # 对端大,本端转 Slave,只能回显对端的序列号 # 相等时没有任何合法分支,实际设备会持续重传 DD 直至邻居超时 raise ValueError("Router ID 冲突,邻居无法完成 ExStart 协商")local_rid与remote_rid都是点分十进制转换后的 32 位整数,比较开销可以忽略——这也是它能被放在报文处理热路径上的原因。真实实现里这个判断在收到 DD 的第一个瞬间就完成,不需要额外的握手往返。
2.2 为什么必须分主从:OSPF 没有 TCP,序列号只能自己造
DD 报文交换的本质,是把整个 LSDB 的目录分页传一遍,页与页之间必须有序、不重、不漏。麻烦在于 OSPF 直接封装在 IP 之上(协议号 89),没有端口、没有滑动窗口、没有重传定时器。想在这样一条「裸链路」上做出有序传输,最省事的办法就是让一端说了算:Master 单方面递增序列号,Slave 只能原样回显。
这个回显同时干了两件事:既是对上一页的隐式确认,又顺带携带了自己那一页的 LSA 头。一次发送换回一次确认加一份数据,握手成本被压到最低。如果换成显式 ACK,DD 报文数量会直接翻倍,而 LSDB 摘要在大网络上动辄几百页。
class DDExchange: def __init__(self, is_master: bool, seq: int): self.is_master = is_master self.seq = seq # 初始值两端各自随机生成,互不相关 self.ack_pending = False def send(self, headers): if self.is_master: self.seq += 1 # 只有 Master 有权递增,这就是「控制权」的含义 self.ack_pending = True return {"ms": int(self.is_master), "dd_seq": self.seq, "lsa": headers} def recv(self, pkt): if self.is_master: # Master 收到的回显,序列号必须与刚发出的一致,MS 位必须是 0 if pkt["dd_seq"] != self.seq or pkt["ms"] != 0: raise OSError("DD 序列号不匹配,重传上一页") self.ack_pending = False else: # Slave 不递增,只把 Master 的序列号抄下来,回显即确认 self.seq = pkt["dd_seq"] return {"ms": 0, "dd_seq": self.seq, "lsa": []}ms字段就是报文头里的 MS-bit,dd_seq是 32 位序列号。真实设备还会处理一个边界:Master 在等待回显期间收到新的 DD,说明对端重传了,此时要按序列号去重而不是报错。
为什么不干脆用接口地址大小、MAC 地址或者随机数来定主从?Router ID 的优势在于三点:全网唯一(手工规划或自动选举保证)、稳定(不随接口 up/down 抖动)、全序(任意两个值必然分出大小)。用接口地址,链路一抖主从关系就翻转,正在传输的 LSDB 摘要要重来;用随机数,双方有可能同时宣布自己赢,还得再加一轮协商。一次比较定胜负,没有平局、没有回退、没有额外报文,这种设计取舍在控制平面协议里很常见。
2.3 OSPFv3 把宣告挪到接口下:地址语义变了,LSA 也得拆
v2 的宣告方式是在区域视图里network 10.0.0.0 0.0.0.255,靠「网络号 + 反掩码」去匹配接口地址,命中的接口就被划进该区域。到了 v3,这个做法整条链路都走不通了,命令变成在接口下使能ospfv3 1 area 0。题库里那道「OSPFv3 在区域视图通过 network 命令通告」的判断题答案是错误,原因不只是命令换了位置,而是背后的地址模型变了。
第一个原因,v3 的报文源地址是链路本地地址fe80::/10。链路本地地址不属于任何规划网段,用反掩码去匹配它没有意义,只能按接口指定。第二个原因,一条链路上可以同时跑多个 OSPFv3 实例,靠报文头里的 Instance ID 区分,而 Instance ID 是接口级配置,区域属性也必须跟着落在接口上。第三个原因,同一个物理接口在不同实例下可以属于不同区域,区域不再是「地址段的属性」,而是「接口的属性」。
LSA 结构也随之重排。v2 的 Router-LSA 里直接挂 stub 网络,拓扑和前缀混在一起;v3 把它拆成两层:Link-LSA(Type 8)在链路上泛洪,携带链路本地地址和链路前缀;Intra-Area-Prefix-LSA(Type 9)负责把前缀关联到 Router-LSA 或 Network-LSA 上。这样拆的直接收益是解耦——改前缀只触发前缀重算(PRC),不触发整棵 SPF 树重算。在一个前缀数量远大于节点数量的网络里,这个差别相当可观。
提示:记 v3 的宣告方式,别死记「接口下配」。记「链路本地地址无法用反掩码匹配」这条因果,命令形式自然就推出来了。
3. 链路状态协议的过滤边界:filter-policy 动的是路由表不是 LSDB
3.1 LSDB 与 RIB 之间的那道闸门
链路状态协议的计算是一条流水线:LSA 泛洪 → LSDB → SPF 计算最短路径树 → 得到候选路由 → 装入路由表(RIB)→ 下发 FIB。filter-policy import这道命令卡在「候选路由 → RIB」这个位置,也就是 SPF 算完之后、装表之前。
这个位置决定了它的全部行为。过滤掉的路由不会进本机路由表,但 LSA 早就泛洪完了,本机 LSDB 里那条 LSA 还在,邻居的 LSDB 里更是在。所以现场会看到一个很典型的组合:display ip routing-table里查不到某条明细路由,但display ospf lsdb能查到对应的 LSA,邻居那边也照常算出了这条路由。
题库里那道「用 filter-policy 在入方向过滤可以阻断链路状态信息传递」判定为错误,根子就在这里。它拦的是「我用不用这条路由」,不是「我知不知道这个拓扑」。
对比距离矢量协议就清楚了。RIP 传的是路由本身,「我把路由表告诉邻居」,所以在出方向做 filter-policy,过滤掉的路由邻居根本收不到,确实能阻断传播。OSPF、IS-IS 传的是拓扑,「我把链路状态告诉邻居,邻居自己算」,你没有权力替邻居决定它算出什么。这个差异是 LS 与 DV 最本质的分野,也是这类判断题反复出现的动机。
# 在 ASBR 上做入方向过滤:只允许 10.10.0.0/16 进入本机路由表 acl number 2000 rule 5 permit source 10.10.0.0 0.0.255.255 rule 10 deny source any quit ospf 1 router-id 10.0.0.1 import-route static cost 100 type 2 filter-policy 2000 import # 作用点:SPF 结果 -> RIB,不是 LSDB quit # 验证两步走:LSDB 里 LSA 应该还在,路由表里应该没有 display ospf lsdb ase 10.20.0.0 display ip routing-table 10.20.0.0cost 100 type 2是引入时的种子度量,不写就按协议默认值走(OSPF 默认 cost 1、type 2),这一点在下一章的坑里还会遇到。filter-policy 2000 import里的2000是基本 ACL 编号,规则匹配的是路由的目的地址前缀,不是报文的五元组。
如果确实要让某个网段的信息根本不进入某个区域,手段是区域划分而不是 filter-policy:Stub 区域靠 ABR 不下发 Type 5 LSA,Totally Stub 再进一步连 Type 3 明细也不下发,NSSA 则相反,允许外部路由以 Type 7 在本区域引入。这些机制动的是泛洪范围,才是真正意义上的「阻断」。
3.2 IS-IS 的网络类型与三次握手:为什么 P2MP 跑不了
IS-IS 只认两种网络类型:广播链路(以太网、令牌环)和点到点链路(PPP、HDLC)。NBMA 网络如 ATM、帧中继,必须把物理接口拆成子接口并把子接口类型配成 P2P 才能跑。至于点到多点(P2MP),协议里压根没有为它预留位置。
原因在 Hello PDU 的设计前提里。IS-IS 的 IIH 假定链路要么是广播域——一个 IIH 发出去所有人都能收到,靠 DIS 周期发 CSNP 同步数据库;要么是严格点对点——一个 IIH 只有一个确定的接收者,靠 3-way 握手确认双向可达。P2MP 是第三种形态:一个物理接口、多个逻辑邻居、但又不构成广播域。它既选不出有意义的 DIS,也没法用一条单播 IIH 一一对应多个邻居,状态机里没有这个中间态。OSPF 能支持 P2MP,是因为它的 Hello 支持单播与组播切换,且在 P2MP 网络类型下干脆不选 DR,两者前提不同。
广播网和 P2P 网保证邻居可靠性的手段也不一样。P2P 链路上用的是 3-way 握手,IIH 里带 TLV 240(P2P Three-Way Adjacency),把本端看到的邻居 System ID 和 Circuit ID 填进去,只有双方都在对方的 IIH 里看到自己,邻居才真正 Up。这个机制专门治单向链路——只有一端能收到 Hello 时,两次握手会建出一个「半开」邻居,路由算出来全是黑洞,3-way 直接把它挡在 Init。
广播网上的双向确认则靠 IIH 里携带的邻居 SNPA 列表:收到对方的 IIH,检查里面有没有自己的 MAC。题库里「广播网络中 IS-IS 通过什么机制保证邻居关系建立的可靠性」给的标准答案是三次握手,考试按这个选;但从机制上分,TLV 240 的 3-way 是三四二点对点链路的原语,广播网用的是 LAN IIH 加 CSNP 的组合。把这两层分清楚,遇到变形题才不会被绕进去。
顺带记一组高频默认值差异:IS-IS 的 DIS 没有备份、默认抢占、广播网 Hello 间隔约 3.3 秒、CSNP 周期 10 秒;OSPF 的 DR 有 BDR、默认不抢占、广播网 Hello 10 秒。判断题最喜欢在这几个数字上做手脚。
3.3 多进程隔离与进程号的本地语义
同一台路由器上跑两个 IS-IS 进程,两个进程的 LSDB 默认完全隔离,一个进程里的链路状态信息不会流到另一个进程。这个「默认隔离」不是实现偷懒,而是语义决定的:进程号本地有效,根本不进报文,一个进程在拓扑上就等于一台独立的路由器。
隔离带来的能力是「一台设备扮演多台」。迁移期两套地址规划并存、把某块网络从 Level-1 整体挪到 Level-2、或者做区域边界而又不想多加一台设备,都靠这个特性。反过来,如果进程间自动互通,区域边界就形同虚设,Level-1 的路由会从一条意料之外的路径串到另一个进程里去。
要让两个进程交换路由,必须显式操作:做 route leaking 把 Level-2 路由泄漏到 Level-1,或者在进程间做路由引入。默认不通、需要时显式打通,这个设计思路和「Router ID 一次比较定主从」是一脉相承的——把不确定性关在门外,让每一条跨边界的路径都是人主动打开的。
4. BGP Update 的属性四象限:哪些字段缺席就是协议错误
4.1 公认必遵、公认可选与两条可选通道
Update 报文的结构是:撤销路由长度、撤销路由、路径属性总长度、路径属性、NLRI。属性区里放的就是各种路径属性,它们按两个维度分类:公认还是可选(每个 BGP 实现是否必须认识),传递还是非传递(能不能穿过 AS 边界继续往下传)。两个维度交叉出四类,构成了整个 BGP 策略体系的地基。
| 属性 | 类别 | 传播范围 | 缺省值 / 说明 |
|---|---|---|---|
| ORIGIN | 公认必遵 | 全程 | 必须存在,取值 i / e / ? |
| AS_PATH | 公认必遵 | 全程 | 必须存在,eBGP 逐跳追加 |
| NEXT_HOP | 公认必遵 | 全程 | 必须存在 |
| LOCAL_PREF | 公认可选 | 仅 IBGP | 默认 100,越大越优 |
| ATOMIC_AGGREGATE | 公认可选 | 全程 | 聚合时打标记 |
| MED | 可选非传递 | 相邻 AS | 默认 0,越小越优 |
| COMMUNITY | 可选传递 | 全程 | 给路由打标签 |
| ORIGINATOR_ID / CLUSTER_LIST | 可选非传递 | 反射器内 | 路由反射防环 |
「Update 中可不包含哪些属性」这类题的答案就藏在「必遵」二字里。ORIGIN 和 AS_PATH 是公认必遵,缺了就是协议错误,对端直接回 Notification,错误码 3(UPDATE Message Error),子码 3(Missing Well-known Attribute),会话当场断掉。LOCAL_PREF 是公认可选且只在 IBGP 内有效,eBGP 发出去时会被剥掉;MED 是可选非传递,本来就不保证携带。所以正确选项是这两个。
# BGP-4 路径属性四象限,按属性码归类 WELL_KNOWN_MANDATORY = {1: "ORIGIN", 2: "AS_PATH", 3: "NEXT_HOP"} WELL_KNOWN_DISCRETIONARY = {4: "LOCAL_PREF", 6: "ATOMIC_AGGREGATE"} OPTIONAL_TRANSITIVE = {7: "AGGREGATOR", 8: "COMMUNITY"} OPTIONAL_NON_TRANSITIVE = {5: "MED", 9: "ORIGINATOR_ID", 10: "CLUSTER_LIST"} def check_update(attrs: dict) -> str: """校验一条 Update 的属性集合是否合规,attrs 的 key 是属性码""" missing = [name for code, name in WELL_KNOWN_MANDATORY.items() if code not in attrs] if missing: # 缺公认必遵属性:回 Notification(3,3) 并中断会话,不是忽略 return f"NOTIFICATION 3/3 Missing Well-known Attribute: {missing}" return "OK"这段校验的关键在最后那个return:缺必遵属性不是「这条路由不要了」,而是「你这个邻居有问题」,处理级别完全不同。理解这一点,才能解释为什么某些异常路由会导致 BGP 会话反复重建而不是简单丢弃。
4.2 Origin 的 IGP > EGP > Incomplete 是怎么排出来的
ORIGIN 有三个取值:i 表示用network命令把本 AS 内的网段宣告进来,路由源自 AS 内部;e 表示从 EGP 学来(早期协议,现在基本绝迹);? 表示用import-route引入,来源不确定,可能是直连、静态或者别的协议。
优先级是 i > e > ?。理由很直白:越「原生」的路由越可信。network宣告的是我自己知道确切出处的网段,import-route引入的是别人给我的、经过一次转换的信息,中间可能丢过属性、改过度量。让原生路由赢,可以避免一条从外部引入的聚合路由把内部的明细路由顶掉——这类故障现场排查起来相当费劲,因为路由表看起来「有路」,但流量走的是另一条。
注意:Origin 不是选路的第一顺位。完整的比较顺序里,它排在 Weight、Local_Pref、本地始发、AS_PATH 长度之后。看到「Origin 优先级最高」这种表述要警惕,那是把「三个 Origin 取值之间的相对顺序」偷换成了「所有属性之间的绝对顺序」。
4.3 Local_Pref 与 MED:一个向内看,一个向外看
这两个属性最容易混,因为它们的取值方向和传播范围正好相反。
LOCAL_PREF 回答的是「本 AS 内部,我更愿意从哪个出口出去」。它是纯粹的 AS 内部策略,传给 eBGP 邻居毫无意义——人家不关心你内部喜欢走哪条路。所以它只在 IBGP 内传播,eBGP 发出去时清空。默认值 100,越大越优。
MED 回答的是「我希望你从哪个入口进来」。它是给外部邻居看的,所以能跨 eBGP 传递,但默认只影响相邻的那一个 AS,不会再往下传。默认值 0,越小越优。
一对数字一正一反、一个 100 一个 0,判断题在这里设置陷阱的成功率极高。记忆锚点可以设成「本地优先一百起,度量开销零开始」。
COMMUNITY 是另一条线。它不影响选路,作用是给一批具有共同特征的路由打上同一个标记,再配合 community-filter 做批量策略。题库里问「用哪种属性对具有共同特征的路由进行标记以便其他路由器识别」,答案只能是它——AS_PATH 会影响选路和防环,MED 表达入口偏好,Origin 表达来源,都不是干标记这活的。
5. 排查与避坑:把「看起来对」的选项做错的六个现场
5.1 作用点错位:控制平面与转发平面
坑一:以为 filter-policy 能挡住 LSA 泛洪。现象是配了入方向过滤后,本机路由表干净了,但display ospf lsdb里那条 LSA 依然在,邻居也照常算出路由。原因是命令作用在 SPF 之后、入 RIB 之前,压根没碰泛洪。解决办法是改用区域机制:Stub 靠 ABR 不下发 Type 5,Totally Stub 连 Type 3 明细也拦掉,NSSA 允许外部路由以 Type 7 在本区域引入;真要按前缀裁剪,就在 ABR 的 summary 上做,而不是指望 filter-policy。
坑二:把路由策略和策略路由当成一回事。现象是配了policy-based-route,路由表纹丝不动,以为命令没生效。原因是策略路由作用在转发平面,逐跳匹配报文、直接改下一跳,不进路由表;路由策略作用在控制平面,改的是路由属性的可达性。前者要每台设备都配,后者靠协议扩散。分不清这两个,配置写完看不出效果还算轻的,严重的情况是策略路由漏配一跳,流量在半路被送回原路。
5.2 默认值幻觉:引入开销、Local_Pref 与 ACL 编号段
坑三:以为路由引入不指定 cost 就会失败。现象是import-route之后路由确实进来了,但度量值是个很小的数字,导致路径次优。原因是每个协议都有自己的默认种子度量,OSPF 引入默认 cost 1、type 2,不是 20。这个「1」在有多条外部路径时会直接把流量拉到自己身上。解决办法是引入时显式写cost和type,并且和对端 ASBR 的规划对齐——两侧不一致会产生非对称路径。
坑四:把 Local_Pref 的默认值记成 0。现象是改优先级时按 0 基准去加,配了个 50 以为提升了,实际是降到了默认值以下。原因是把 LOCAL_PREF 和 MED 的默认值混了:前者默认 100,后者默认 0。解决很简单,配置前先display bgp peer verbose看一眼当前生效值,别凭记忆改。
坑五:ACL 编号段记混。现象是配了个 4000 的 ACL 想做三层流量过滤,结果匹配不上。原因是编号段本身就带语义:基本 ACL 2000–2999,高级 ACL 3000–3999,二层 ACL 4000–4999,用户自定义 ACL 5000–5999,用户 ACL 6000–6031。编号选错,匹配的字段维度就错了。这条没有别的办法,把这五行记住,或者养成用命名 ACL 的习惯。
5.3 冗余与选举:VRRP 抢占、堆叠分裂与 RSTP 计时器
坑六:以为 VRRP 默认不抢占。现象是备份组运行一段时间后,明明优先级更高的设备恢复了,却没有拿回 Master。真实情况恰好相反:缺省是抢占的,且抢占延迟为 0。不抢占反而要显式配置。要让网络稳定,通常配一个几秒的抢占延迟,等上联链路和路由完全收敛再切,否则会出现「抢回来又切走」的来回抖动。这个延迟值不是玄学,按 IGP 收敛时间加余量给就行。
同类问题还有两个高频项。堆叠分裂后,两个系统拥有完全相同的全局配置,IP 和堆叠系统 MAC 不会立即变化,正因为「看起来完全一样」才必须靠 MAD 检测打破僵局,检测失败的一方关闭除保留端口外的所有物理端口,避免双主。RSTP 判断邻居失效的阈值是连续 3 个 Hello Time 收不到 BPDU,不是 4 个;TC-BPDU 防护的阈值默认是每个 Hello Time 处理 1 个拓扑变化报文,且配置在全局而非接口下。这几个数字和位置,是判断题最爱的下手处。
6. 从背题到建模:三个提问把边界条件问出来
题库做多了会发现一个规律:真正拉开分数的不是记住了多少结论,而是能不能在看到一句描述时,条件反射地追问三件事——作用点在哪、默认值是多少、范围有多大。
作用点决定了一条命令改的是数据库还是路由表、是控制平面还是转发平面。filter-policy 与区域划分的差别、路由策略与策略路由的差别,全是这一问的产物。默认值决定了「不配」和「配了但没写参数」的实际效果,引入开销、Local_Pref、Hello 计时器、TC-BPDU 阈值,全部落在这里。范围决定了机制的适用边界,IS-IS 不支持 P2MP、OSPFv3 不能在区域视图宣告、Local_Pref 不跨 AS、MED 只影响相邻 AS,讲的都是「到哪里为止」。
这三问本质上是在给每个知识点建一个三维坐标,而不是存一条扁平的文字。坐标建起来之后,题目怎么变形都能落回原位;只有文字,题干换个词就找不到北。
验证方法也顺着这三问走。想看作用点,就用display ospf lsdb和display ip routing-table对照着看——两边不一致的地方,就是过滤发生的位置。想看默认值,就在配置前先display一遍当前生效值,改完再display一遍,别靠记忆。想看范围,就抓包:DD 报文里的 MS 位和序列号能直接印证主从关系,IS-IS 的 TLV 240 能直接印证 3-way 握手是否完成,BGP 的 Update 里属性码的缺席能直接印证「必遵」二字的份量。抓包是把选择题变成观察题的最短路径,比反复读解析有用得多。
有一份持续更新的题库在手边,价值不在于多刷几遍,而在于它提供了一个足够密集的「边界样本集」——每一道错题都是一次坐标校准的机会。我自己的血泪经验是:错题不要只记正确答案,要顺手在边上写一行「作用点 / 默认值 / 范围」的具体内容,写不出来说明这个点还没建坐标,那就回去翻机制,别急着做下一题。从那以后我每次遇到判断题,都强制把这三个问题在心里过一遍,正确率的变化比多做两百道题明显得多。这份 2024 数通 H12-831 新题库连同解析就在下载包里,配合上面这套三问自检法一条条过,比单纯背答案走得远。希望帮到你。
本文还有配套的精品资源,点击获取