别再“翻译”CLI了!从Juniper、华为的YANG模型学习优秀的数据建模思想
从CLI翻译到数据建模:解码Juniper与华为的YANG设计哲学
当第一次打开Juniper的YANG模型文件时,我被一种优雅的层次结构震撼了——这完全不是对命令行参数的简单映射,而是一个精心设计的网络配置数据宇宙。反观许多团队的设计文档,却充斥着类似"set interfaces ge-0/0/1 unit 0 family inet address 192.168.1.1/24"的直译式建模。这种认知偏差正是导致YANG模型难以维护和扩展的根源。
1. CLI翻译陷阱:为什么你的模型越改越乱
去年参与某运营商SDN项目时,我们团队花了三个月重构一个"CLI式"YANG模型。原始设计者将每个配置命令直接转换为YANG节点,导致模型中出现大量冗余路径。比如 /interfaces/interface[name='ge-0/0/1']/unit[id='0']/family/inet/address/ip-prefix 这样的嵌套结构,实际上完全可以用更简洁的 /interfaces/interface/ipv4-address 表达。
典型CLI翻译模型的三大缺陷 :
- 结构膨胀 :每个CLI参数都生成独立节点,模型体积呈指数增长
- 语义丢失 :
set protocols ospf area 0.0.0.0 interface ge-0/0/1变成机械的路径映射,失去网络拓扑的抽象含义 - 扩展困难 :新增特性时被迫添加平行节点,而非扩展现有对象模型
华为在NE40E路由器YANG模型中展示了一个精妙的反例。其BGP模块没有简单复制 bgp 65000 这样的CLI结构,而是构建了真正的自治系统对象模型:
module huawei-bgp {
container bgp {
leaf as-number {
type inet:as-number;
}
container peers {
list peer {
key "address";
leaf address {
type inet:ip-address;
}
// 对等体属性作为peer的子节点
}
}
}
}
2. 对象建模思维:大厂模型的隐藏语言
Juniper的YANG模型库像是一本网络协议的面向对象设计教科书。以接口配置为例,他们创造了三个逻辑层次:
| 建模维度 | CLI思维实现 | Juniper对象模型 |
|---|---|---|
| 物理接口 | 独立配置每个端口 | physical-interface 资源池 |
| 逻辑接口 | 绑定到具体端口 | 可跨设备的 logical-interface 抽象 |
| 协议栈 | 逐接口配置 | 全局 protocols 层次结构 |
这种设计最精妙之处在于 倒置了配置依赖关系 。传统CLI思维要求先配物理接口才能配IP地址,而Juniper模型允许先定义逻辑接口再绑定到任意物理端口——这正是网络虚拟化的核心需求。
对象建模的黄金法则 :
- 识别核心业务实体 (如路由器、接口、路由协议)
- 定义实体间关系 (包含、引用、继承)
- 分离配置与状态数据 (config true/false的明智使用)
- 预留扩展点 (通过feature和deviation机制)
华为在MPLS-VPN模型中的设计更令人叫绝。他们没有创建 vpn-instance 这样的扁平列表,而是构建了完整的服务模型:
module huawei-l3vpn {
container l3vpn {
container vpn-services {
list vpn-service {
key "name";
leaf name { type string; }
container endpoints {
list endpoint {
key "id";
uses interface-attachment;
uses routing-policy;
}
}
}
}
}
}
3. 模型考古学:从开源YANG中逆向工程设计思维
当拿到一个厂商的YANG模型时,我习惯进行"四层解剖":
- 命名空间探秘 :
ietf-前缀表示标准实现,vendor-前缀通常包含特殊扩展 - 模块依赖图 :
import语句揭示了功能边界划分智慧 - 关键扩展点 :查找
deviation和feature定义了解厂商差异化策略 - 状态机设计 :
operational状态与config的交互方式反映实现架构
以OpenConfig的接口模型为例,其 /interfaces/interface 结构隐藏着深刻的设计哲学:
interfaces
+-- interface*
+-- config
| +-- name
| +-- type
| +-- mtu
+-- state
| +-- oper-status
| +-- counters
+-- subinterfaces
+-- subinterface*
这种 严格区分配置与状态 的做法,使得网管系统可以清晰界定管理边界。而许多自研模型常犯的错误是将 config 和 state 混在同一层级,导致配置下发与状态采集相互干扰。
4. 思维训练场:从阅读者到设计者的蜕变
培养YANG建模思维需要刻意练习。我的建议是从小模块开始:
- 选择标准协议 (如OSPF、BGP)
- 对比三家实现 :IETF标准模型、OpenConfig抽象、厂商具体实现
- 绘制对象关系图 :用PlantUML还原设计者的思维过程
- 编写差异报告 :记录各版本的设计取舍
一个进阶技巧是 模型变形测试 :修改现有模型的某些结构,预测其对北向API和南向实现的影响。例如尝试将Juniper的层次化接口模型扁平化,就能立即体会到原始设计的精妙之处。
在最近一次网络自动化项目中,我们借鉴了华为YANG模型的 feature 机制。通过定义 feature "advanced-qos" ,实现了基础功能与增值功能的优雅分离:
module acme-qos {
feature basic-qos {
description "Standard queuing support";
}
feature advanced-qos {
if-feature basic-qos;
description "Hierarchical QoS with policing";
}
container qos {
// 基础QOS节点
when "feature-enabled('basic-qos')";
container hqos {
// 高级QOS节点
when "feature-enabled('advanced-qos')";
}
}
}
这种设计使得我们的控制器可以动态识别设备能力,而不是通过硬编码的型号判断。当客户升级license时,北向API自动呈现新的配置层级——这正是优秀数据建模带来的架构弹性。
更多推荐


所有评论(0)