首页 / 资讯中心 / 文章详情

单区域OSPF实验全解析:邻居、LSDB与路由收敛

单区域OSPF实验全解析:邻居、LSDB与路由收敛 ★ FEATURED ARTICLE
1. 从“能通”到“懂为什么通”单区域 OSPF 实验要解决的真问题很多刚接触路由协议的朋友第一次配 OSPF 的心态其实很朴素——把network命令敲上去看邻居起来、路由表里冒出对端网段截个图实验就算完事。我带过几批刚入行的同事十有八九都是这么干的。问题在于这种“能通就行”的验证方式把 OSPF 最有价值的部分全跳过去了为什么邻居有的能到FULL、有的卡在2-WAY为什么明明邻居起来了路由却没进表为什么同一区域里两台设备的Router ID一变整个拓扑的重启行为就跟着变单区域 OSPFSingle-Area OSPF是所有 OSPF 知识的“母体实验”它把多区域带来的复杂度先剥掉只留下最核心的四件事邻居怎么建立、数据库怎么同步、最短路径怎么算、路由怎么进表。把这四件事在同一个小拓扑里跑通、抓包看穿、再故意打坏几个地方验证恢复路径你对 OSPF 的理解才算真正落地。后面接多区域、接外部路由重分发、接特殊区域类型都是在这个骨架上挂肉。这篇内容适合两类人一类是正在准备网络方向认证、需要把理论落到命令行上的朋友另一类是已经在现网接触过 OSPF、但一直靠“抄配置”过日子想搞清楚每条命令到底在干什么的运维同学。我会用一个四台路由器的小型实验拓扑把单区域 OSPF 从零配到全收敛然后把常见的翻车点在中间挨个拆开讲——包括邻居状态机的真实含义、Hello与Dead定时器的隐性匹配要求、Router ID的选举顺序、DR/BDR在多路访问网络上的作用以及最容易被忽略的MTU与认证不一致问题。需要先说明一点文中涉及的具体地址规划、设备型号、拓扑规模都是基于我自己的实验环境做的合理设计属于常见实践不代表某种唯一标准。你在自己的环境里完全可以换一套地址段只要逻辑对应即可。提示单区域实验虽然简单但请务必先画拓扑、再写地址表。我见过太多人一边连一边改最后自己都不知道哪个口是哪个网段排错时连基线都没有。2. 实验环境的取舍为什么这个拓扑是四台而不是两台2.1 拓扑规模与角色划分两台路由器跑 OSPF 确实能验证邻居建立但它验证不了很多东西验证不了DR/BDR的选举因为点对点链路根本不需要验证不了ABR的行为差异因为只有一个区域验证不了等价路由和路径选择的差异因为只有一条路径。所以我建议单区域实验至少上四台把它做成“中心 分支”的结构设备角色定位接口规划所属网段R1核心汇聚同时充当DR优先候选G0/0、G0/1、Lo010.1.12.0/24、10.1.13.0/24、1.1.1.1/32R2接入侧参与广播网段选举G0/0、G0/2、Lo010.1.12.0/24、10.1.23.0/24、2.2.2.2/32R3接入侧与 R2 形成第二条路径G0/1、G0/2、Lo010.1.13.0/24、10.1.23.0/24、3.3.3.3/32R4纯末梢验证设备只挂一个网段G0/0、Lo010.1.24.0/24、4.4.4.4/32这个结构有意思的地方在于R1、R2、R3 三者两两相连形成一个三角形。三角形在 OSPF 里意味着存在冗余路径于是DR/BDR选举、SPF的最短路径计算、等价路由的判定全都有戏可看。R4 则是用来验证“非直连网段能否被正确学习到”的对照组——它自己只跑一个接口的 OSPF路由表里应该能看到 10.1.12.0/24、10.1.13.0/24、10.1.23.0/24 三条远端路由且下一跳都指向 R2。为什么不把 R4 也接进三角形因为那会让拓扑变成四个节点的全互联LSA泛洪的路径变多抓包时干扰项太多第一遍做实验容易被淹没。先做减法再做加法这是我在教学实验里一贯的顺序。2.2 接口类型带来的行为差异这里有个特别容易踩的点不同厂商、不同接口类型下OSPF 的默认网络类型不一样。以太网口默认是broadcast会触发DR/BDR选举串口如果环境里有默认是point-to-point不选举而Loopback口默认是loopback类型其通告的掩码永远是/32不管你在接口上配的是什么掩码。我实际测试时就吃过这个亏一开始在 R1 的Lo0上配了1.1.1.1/24结果邻居那边收到的是一条1.1.1.1/32的主机路由。当时还以为是邻居配错了折腾了十几分钟才反应过来是loopback网络类型的默认行为。所以如果你希望Loopback通告真实掩码需要显式改成ip ospf network point-to-point这个细节后面的小节还会展开。选G0/0这类千兆以太口做互联有个好处抓包方便而且broadcast类型能把DR/BDR的选举过程完整暴露出来。如果你手头只有虚拟环境用veth或者虚拟交换机连出来的口同样走broadcast行为一致可以放心用。3. 从零配置每一步背后的意图3.1 基础地址与进程启动配置顺序我建议固定为接口地址 → 进程与Router ID→network宣告 → 验证。这个顺序不是强迫症而是因为Router ID如果依赖接口地址自动选举在接口还没up的时候选举结果是不确定的会导致实验不可复现。以 R1 为例基础配置如下命令风格按常见设备习惯书写实际以你所用设备的语法为准# R1 接口地址 interface GigabitEthernet0/0 ip address 10.1.12.1 255.255.255.0 no shutdown interface GigabitEthernet0/1 ip address 10.1.13.1 255.255.255.0 no shutdown interface Loopback0 ip address 1.1.1.1 255.255.255.255 # R1 OSPF 进程 router ospf 1 router-id 1.1.1.1 network 10.1.12.0 0.0.0.255 area 0 network 10.1.13.0 0.0.0.255 area 0 network 1.1.1.1 0.0.0.0 area 0注意network后面跟的是反掩码wildcard mask不是子网掩码。这是新手第一个高频错误10.1.12.0 0.0.0.255表示匹配 10.1.12.0/24 这个范围而10.1.12.0 255.255.255.0在多数设备上会被直接拒绝或产生意外的匹配范围。反掩码的规则是“0 表示必须精确匹配1 表示任意”所以/24对应0.0.0.255/32对应0.0.0.0这个换算关系一定要形成肌肉记忆。为什么要显式指定router-id因为它决定了 OSPF 数据库里每条LSA的标识。如果靠自动选举设备会先看有没有手工配置的router-id没有就取所有up状态的Loopback口里最大的 IP再没有才取物理口里最大的 IP。这个规则本身没问题问题在于接口状态是动态的——今天Lo0是up的选举出 1.1.1.1明天Lo0被shutdown了Router ID就变了而Router ID变更会引发整个进程的邻居重建。在实验里这会让你误以为“配置没问题但邻居总掉”非常折磨人。3.2 宣告网段的两种思路network宣告有两种常见写法我一般推荐精确宣告互联口 精确宣告 Loopback而不是图省事写一个network 10.0.0.0 0.255.255.255 area 0把整个 10.0.0.0/8 都扔进去。原因有二。第一大范围宣告会把不该跑 OSPF 的接口比如管理口、测试口也卷进协议导致Hello报文从意想不到的接口发出去邻居表里多出莫名其妙的条目。第二大范围宣告会让路由表里的条目变得“对不上号”排错时你没法通过路由表快速判断哪条路由来自哪个接口。精确宣告 可追溯这个原则在后面的多区域实验里会更重要因为网段宣告位置直接决定了它属于哪个区域、会以什么类型的LSA泛洪出去。有一个例外场景值得单独提如果你用network 0.0.0.0 255.255.255.255 area 0这种“全匹配”写法效果是把所有接口都拉进 OSPF。这种写法在快速搭建测试环境时确实省事但在有多个协议共存、或者有NAT内外网区分的设备上会带来相当隐蔽的问题。我的态度是实验环境可以图快但只要涉及“要给别人看”或者“要长期跑”的配置一律精确写法。3.3 四台设备的宣告对照把 R2、R3、R4 按同样思路配完宣告关系如下表。这张表建议在实验时直接抄在旁边排错时对着看设备Router ID宣告的网段所属区域R11.1.1.110.1.12.0/24、10.1.13.0/24、1.1.1.1/32area 0R22.2.2.210.1.12.0/24、10.1.23.0/24、2.2.2.2/32area 0R33.3.3.310.1.13.0/24、10.1.23.0/24、3.3.3.3/32area 0R44.4.4.410.1.24.0/24、4.4.4.4/32area 0R4 只和 R2 相连它的 OSPF 进程里只宣告 10.1.24.0/24所以它对端到端拓扑的全部认知都来自 R2 泛洪过来的LSA。这个“只靠信息传递建立全局视图”的过程正是 OSPF 最值得观察的地方——后面讲LSDB同步时会重点展开。4. 邻居建立过程状态机里的每一步都在说明什么4.1 从 Down 到 FULL 的真实顺序show ip ospf neighbor输出的那一列状态很多人只记住“FULL就是好的”但排错时真正有用的是知道卡在哪个状态意味着哪类问题。完整状态迁移是DOWN → INIT → 2-WAY → EXSTART → EXCHANGE → LOADING → FULL每一步都有明确的触发条件。DOWN是初始态表示还没收到对方任何Hello。发出第一份Hello后如果收到对方的Hello且对方的Hello里没有自己的Router ID就进入INIT——说明单向通到了对方但对方还没听见你。双向都听见了状态变2-WAY。2-WAY这个状态是最容易被误解的。在有DR/BDR选举的广播网络上非 DR 也非 BDR 的路由器之间状态会稳定停留在2-WAY这是正常的设计不是故障。原因是同一网段上的DROther之间不需要建立完整的邻接关系它们只需要和DR、BDR建立FULL所有LSA通过DR中转。所以如果你在一个三台以上设备共用的网段上看到两个2-WAY不要慌先看DR/BDR是谁。EXSTART阶段开始交换DBD数据库描述报文此时会进行主从协商Router ID大的一方成为Master负责控制后续DBD的序列号。这里就会出现一个经典问题如果两台设备的接口MTU不一致EXSTART会反复重传、卡死在EXSTART或不断回落到EXCHANGE。因为DBD报文携带MTU信息一方发现另一方的MTU比自己大时会拒绝接受。这个坑我后面会专门用一节讲。EXCHANGE交换DBD摘要LOADING根据摘要请求缺失的完整LSA用LSR/LSU/LSAck三轮交互全部收齐后进FULL。FULL的含义是“两边的链路状态数据库完全一致”而不是“能通”。这一点必须分清——数据库一致是路由计算的前提而能通是计算结果正确之后的结果。4.2 DR 与 BDR 的选举规则与实验观察广播网络上的选举逻辑我一般用一句话概括先比接口优先级优先级相同比Router IDRouter ID大的赢优先级为 0 的接口不参与选举。默认优先级是 1所以如果什么都不配赢家就是Router ID最大的那台——在我们的拓扑里10.1.12.0/24 网段上 R11.1.1.1和 R22.2.2.2相比R2 会成为DR这通常和“核心设备应该是 DR”的直觉相反。这里有个关键机制必须点出来选举不是抢占式的。如果DR已经选出来了此时再接入一台优先级更高的设备它不会把现任DR顶下去除非现任DR失效或者你手动清除 OSPF 进程。这个设计是为了避免网络频繁震荡但在实验里会造成“我明明配了高优先级为什么它不是 DR”的困惑。解决办法是改完优先级后执行clear ip ospf process重置进程或者干脆把设备重启顺序控制好。我通常会在 R1 的 G0/0 上做两个动作来验证这套规则# 让 R1 在 10.1.12.0/24 上成为 DR interface GigabitEthernet0/0 ip ospf priority 100 # 验证当前选举结果 show ip ospf interface GigabitEthernet0/0输出里会明确列出Designated Router和Backup Designated Router的Router ID以及本接口的优先级。改完优先级如果没生效别怀疑配置先确认是不是需要触发一次重新选举。注意把某台设备的接口优先级调成 0是让它“永不参选”这个技巧在多路访问网络里很有用——比如你想让一台低性能设备只做DROther避免承担泛洪中转职责。还有一个观察点值得做R1、R2、R3 三角互联在 10.1.12.0/24 和 10.1.13.0/24 两个广播网段上DR/BDR的归属可能不同。把两个网段的选举结果都记下来你会发现“同一台设备在不同网段上角色不同”是完全正常的这正是DR的按接口per-interface属性。5. 链路状态数据库与路由表从 LSDB 到转发平面的完整链路5.1 LSDB 里的 LSA 类型与本次实验能看到的条目单区域实验虽然简单但LSDB里至少会出现两类LSAType 1Router LSA和Type 2Network LSA。Type 1 由每台路由器产生描述“我有哪些接口、连了哪些邻居、哪些是stub网段”Type 2 由DR产生描述“这个广播网段上有哪些路由器”。用show ip ospf database能看到本区域所有LSA的摘要。我建议你在实验时把这个输出和拓扑图并排放着看Type 1 的Link ID是产生它的路由器的Router IDADV Router也是它自己Type 2 的Link ID是DR接口的 IPADV Router是DR的Router ID。看懂了这两个字段的对应关系你就理解了 OSPF 数据库的“索引方式”。这里有个实践中的小技巧先看LSDB再看路由表。如果两台设备的路由表不一致第一步不是去比对路由表而是比对两边的LSDB是否一致。LSDB一致而路由表不一致问题出在SPF计算或路由优选上LSDB不一致问题在泛洪或邻居关系上。这个排查顺序能把问题范围直接砍一半。5.2 路由表的读法与开销计算show ip route ospf的输出里每条路由后面跟着[110/2]这样的标记110是 OSPF 的管理距离2是这条路由的度量值cost。cost 的计算公式是参考带宽 / 接口带宽默认参考带宽是 100 Mbps所以千兆口算出来是 0.1但 OSPF 的 cost 是整数最小取 1因此所有千兆及以上接口的默认 cost 都是 1。这个默认值在现代网络里其实是个坑千兆和万兆算出来都是 1等于没法区分链路优劣SPF在选路时会认为两条路径等价从而做出不符合实际带宽的决策。解决方式是用auto-cost reference-bandwidth把参考带宽调高比如调到 1000010 Gbps这样千兆口算出来是 10万兆是 1区分度就出来了。注意参考带宽的配置必须在同一区域内的所有路由器上保持一致。如果一边是 100 Mbps、一边是 10 Gbpscost 的计算基准不同两台设备算出的最短路径可能指向不同方向形成路由环路。这是我在真实环境里排查过的真实故障症状是“去程走 A、回程走 B且时通时不通”。在四台设备的拓扑里R4 到 1.1.1.1/32 的路径是唯一确定的R4 → R2 → R1cost 分别是 1 1 2所以路由表里会显示[110/2]。如果我把 R2 的 G0/0 带宽改小cost 变大R4 的这条路由的度量值也会跟着变但因为拓扑是单路径的下一跳不会变。真正的路径选择差异要靠在 R1/R2/R3 三角里制造成本差来观察比如把 R1-R3 之间的链路 cost 手动调大看 R3 去往 R2 侧网段时是否改走 R1 中转。5.3 等价路由与负载均衡的验证三角拓扑的一个好处是能造出等价路径。假设 R1 到 2.2.2.2/32 有两条路直连 R2cost 1或者经 R3 再到 R2cost 2。默认情况下 OSPF 只选 cost 小的那条不会负载均衡。但如果我把 R1-R3 和 R3-R2 的链路带宽放大、把 R1-R2 的 cost 调大到 2两条路径的 cost 就都是 2 了此时路由表里会出现两条等价路由默认最多支持 4 条可配。验证负载均衡最直观的方式是用traceroute看路径是否轮换或者用show ip cef 目的地址看转发平面里是否有多个下一跳。这里要提醒一句控制平面的等价不等于转发平面的等价某些平台的 CEF 哈希算法会因为源目地址固定而总是选同一条导致traceroute看起来只有一条路径。这时候要换不同的源地址多试几次或者直接看show ip cef的输出别只凭traceroute下结论。6. 实验中最容易翻车的六个点现象、根因与处置6.1 邻居卡在 INIT 或一直起不来INIT卡住的典型原因是单向通信A 能收到 B 的HelloB 收不到 A 的。在实际环境里这可能是链路只通了一个方向、或者某侧接口被ACL拦了224.0.0.5/224.0.0.6这两个组播地址。OSPF 的Hello是发往224.0.0.5AllSPFRouters的组播DR向DROther发送更新时用224.0.0.6AllDRouters。如果你在某侧接口上配了入方向ACL且没放行这两个地址邻居就永远起不来而且show命令不会直接告诉你“被 ACL 拦了”只能靠抓包看到Hello只有单向。排查顺序我一般是先ping直连地址确认 IP 层通再show ip ospf interface确认两边都在同一区域、Hello/Dead定时器一致然后抓包确认双向都能看到Hello。三步走下来基本能定位。不要一上来就clear ip ospf process清进程会掩盖现场下次再出问题你还是不知道原因。6.2 区域 ID 不一致与定时器不匹配Hello报文里携带了区域 ID、Hello间隔、Dead间隔、认证类型和认证数据、Stub区域标志。这五项必须全部一致邻居才能建立。现实中最常见的是区域 ID 写错比如area 0写成area 1和定时器不一致。有一类特别隐蔽的情况Hello间隔和Dead间隔必须成比例匹配。默认是Hello 10s / Dead 40sDead通常是Hello的 4 倍。如果你把Hello改成 5s 但忘了改Dead或者只在一侧改了邻居会在建立后不断因为Dead超时被拆除表现为“邻居起来了又掉反复震荡”。看show ip ospf interface里的Timer intervals configured那一行两边对一下就能发现。6.3 MTU 不一致导致卡在 EXSTART这是我个人认为单区域实验里最值得亲手复现一次的故障。DBD报文里带了接口MTU当一方发现对端的MTU比自己大时会拒绝继续协商状态就卡在EXSTART反复重传。触发方式很简单把 R2 的 G0/0MTU改成 1400R1 保持 1500然后重置邻居。# R2 侧修改 MTU 触发 EXSTART 卡死 interface GigabitEthernet0/0 ip mtu 1400现象是show ip ospf neighbor里对方一直显示EXSTART同时可能有日志提示OSPF-5-ADJCHG: Process 1, Nbr ... from EXSTART to DOWN, Neighbor Down: Too many retransmissions。两种修法要么两边MTU对齐要么在较小MTU的一侧加ip ospf mtu-ignore。我倾向于对齐 MTU因为mtu-ignore只是跳过检查真正的MTU差异在传大包时仍会出问题比如大尺寸LSU被丢弃属于把问题藏起来而不是解决。6.4 认证配置不一致OSPF 支持明文和MD5两类认证部分平台还支持更现代的摘要算法。认证不一致的表现很干脆Hello直接被丢弃邻居起不来抓包能看到Hello里认证字段对不上。配置时必须注意认证是逐接口配置的而且同一网段所有设备必须一致。我见过有人在一侧配了MD5、另一侧配了明文然后花半小时在查区域 ID。# 接口级 MD5 认证示例 interface GigabitEthernet0/0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 YourKeyHere提示认证密钥变更时建议先在一侧加新密钥保留旧密钥等邻居用新密钥建立后再删旧密钥避免瞬间断邻居。这个“平滑轮换”的思路在现网变更里非常实用。6.5 Loopback 掩码变 /32 的意外前面提过loopback网络类型的默认行为。很多人配ip address 1.1.1.1 255.255.255.0期望宣告 1.1.1.0/24结果邻居收到的路由是 1.1.1.1/32于是判定“掩码不对、配置有问题”。其实这是规范行为不是故障。如果确实需要按真实掩码通告改成ip ospf network point-to-point即可。这个特性还有个正面用法如果你希望某台设备的Loopback只作为Router ID和管理地址使用、不希望它代表整个网段那就保持默认的/32反而是最干净的。知道默认行为是什么、为什么是这样比记“要改还是不要改”重要得多。6.6 被动接口漏配导致 Hello 外发passive-interface的作用是让某个接口参与网段宣告、但不发Hello、不建邻居。典型用法是把连接终端、连接外部网络、或者纯管理口的接口设为被动防止Hello从这些口泄漏出去。我踩过的坑是把连接测试仪的接口忘了设被动结果测试仪上的抓包工具抓到一堆Hello还“发现”了一个不存在的邻居。排查半天才发现是自己的配置问题。正确做法是在进程下统一配置router ospf 1 passive-interface default no passive-interface GigabitEthernet0/0 no passive-interface GigabitEthernet0/1“默认全被动、再把需要建邻居的口放出来”这个写法比逐个口设被动安全得多尤其是在接口数量多的设备上。默认收紧、显式放开这条原则在网络安全配置里通用。7. 验证清单与进阶延伸把一次实验的价值榨干7.1 一份可复用的收敛验证清单实验配完不算完我每次做完单区域实验都会按下面这张清单逐项过一遍确认自己真的理解了而不是碰巧通了验证项命令期望结果邻居状态show ip ospf neighbor所有互联口对端为FULL同网段DROther间为2-WAY接口参数show ip ospf interface brief区域、cost、优先级、网络类型符合设计数据库一致性show ip ospf database各设备看到的 Type 1/Type 2LSA数量一致路由表show ip route ospf远端网段齐全下一跳与 cost 符合最短路径端到端连通ping/traceroute各Loopback之间可达路径与设计一致冗余路径show ip cef 目的存在等价路径时能看到多个下一跳故障恢复断开一条链路后观察邻居DOWN、路由撤销、备用路径接管时间可接受这张表里最容易被跳过的是“数据库一致性”和“故障恢复”。前者能帮你建立“先看数据库再看路由表”的排查习惯后者能让你实测一次 OSPF 的收敛速度——断开链路到备用路径生效通常在秒级具体取决于Dead定时器和SPF计算量。我实测下来默认参数下 40 秒的Dead定时器意味着最坏情况下要等近 40 秒才会判定邻居失效这对很多业务来说太慢了。所以现网里经常会把Hello/Dead调小比如Hello 3s / Dead 12s但要注意这只能在同一网段内一致且会增加协议报文开销。7.2 从单区域往多区域走的衔接点单区域实验跑通之后往多区域延伸时有几个自然的观察点顺手做掉能省下后面很多困惑。第一个是ABR的角色。把 R1 和 R2 之间的链路改成area 1R1 就成了ABR。此时你会看到LSDB里出现 Type 3Summary LSA由ABR产生用于把area 1的网段摘要通告进area 0。对比一下 Type 1 和 Type 3 的Link ID含义差异你会立刻理解“为什么区域间路由的 cost 是从ABR算起而不是端到端累积”。第二个是LSA泛洪的边界。单区域里任何拓扑变化都会让区域内所有路由器重算SPF划分区域后area 1内部的链路震荡不会触发area 0的SPF重算只会在ABR上产生一条新的 Type 3。这个对比能让你直观感受到分区的价值——不是为了“看起来专业”而是为了把拓扑变化的传播范围限制住。第三个是虚链路和骨干区域的连续性。单区域实验里完全碰不到这个问题但一旦区域划分不当比如area 1没有直连area 0就得用虚链路打通。我不建议在第一次做实验时就上虚链路容易把基础概念搅乱。先把单区域的邻居、数据库、路由三件事吃透再往上叠这个节奏我试过多次是最稳的。7.3 现网迁移时我会坚持的几个习惯最后分享几个从实验过渡到现网时我自己一直坚持的做法都是从翻车里攒出来的。第一改 OSPF 参数前先记录基线。把当前的show ip ospf neighbor、show ip ospf database、show ip route ospf三份输出存下来改完再对比。没有基线你根本无法判断变化是“配置生效了”还是“别的地方早就坏了”。第二Router ID一律手工指定且全网规划。不要依赖自动选举也不要用临时地址凑数。Router ID冲突会导致LSA被覆盖、数据库异常症状非常诡异比如路由时有时无排查成本极高。规划时用Loopback地址作为Router ID是常规做法但一定要保证唯一性。第三变更窗口内避免同时改多个变量。改cost、改优先级、改定时器一次只动一个验证完再动下一个。同时改三个参数然后邻居起不来你根本不知道是哪个引起的。这个道理谁都懂但赶进度的时候最容易犯。第四抓包是终极手段但要先想清楚抓什么。OSPF 的Hello、DBD、LSR、LSU、LSAck五类报文各有明确的触发条件抓包前先明确“我怀疑是哪一步出了问题”然后过滤对应报文ospf协议号 89。无脑抓全量包再逐帧翻效率极低而且容易在大量Hello里迷失。单区域 OSPF 的实验价值不在于它能配通而在于它是一个可以反复“弄坏再修好”的沙盒。邻居状态的每一次卡顿、数据库的每一条差异、路由表的每一个 cost背后都有明确的机制在支撑。把这些机制摸透比记住十条配置命令有用得多。
阅读完成 · 觉得有帮助?
咨询建站