4. YANG 数据建模语言:基础语法、模块结构与数据类型
YANG(Yet Another Next Generation)是 IETF 标准化的数据建模语言(RFC 7950),用于定义网络设备配置数据、状态数据、远程过程调用(RPC)和通知的结构与约束。在控制平面接口调用与基线核验自动化中,YANG 是 NETCONF/RESTCONF 操作的核心契约,理解其语法与结构是编写自动化脚本、解析设备能力与生成基线模板的前提。
4.1 YANG 模块结构
一个 YANG 模块由头部声明、导入/包含语句、正文定义三部分组成。模块是 YANG 数据模型的基本容器,通常对应一个功能领域(如接口、路由、ACL)。
| 组成部分 | 关键字/语法 | 说明 |
|---|---|---|
| 模块头部 | module <name> { |
声明模块名称,必须唯一 |
| 命名空间 | namespace "<uri>"; |
定义 XML 命名空间,避免节点冲突 |
| 前缀 | prefix <short>; |
模块内引用本模块时的缩写 |
| 导入 | import <module> { prefix <pre>; } |
引用外部模块的类型或分组 |
| 包含 | include <submodule>; |
引入同一模块的子模块 |
| 正文定义 | container / leaf / list / leaf-list / rpc / notification |
核心数据与操作定义 |
模块结构示例(简化):
module example-interface {
namespace "http://example.com/ns/interface";
prefix if;
import ietf-yang-types { prefix yang; }
container interfaces {
list interface {
key "name";
leaf name { type string; }
leaf type { type enumeration { enum ethernet; enum loopback; } }
leaf enabled { type boolean; default true; }
}
}
}
4.2 YANG 基础语法
YANG 语法采用类似 C 风格的花括号块结构,语句以分号结尾。核心语法规则包括:
- 关键字与标识符:关键字小写(如
container、leaf、list);自定义标识符可包含字母、数字、连字符、下划线,不能以数字开头。 - 语句结构:
keyword [argument] { substatements; },其中 argument 可以是字符串、数字或引用。 - 注释:支持单行
//和多行/* ... */注释。 - 引用与路径:使用
prefix:node-name格式引用外部模块节点;../表示父级路径。 - 必须声明:
mandatory true;强制节点在配置中必须存在。 - 默认值:
default <value>;为 leaf 指定默认值。
语法避坑:YANG 对缩进不敏感,但建议使用 4 空格缩进增强可读性。分号遗漏是初学者最常见的语法错误,尤其在嵌套块结束时容易忘记。
4.3 数据类型系统
YANG 提供丰富的内置数据类型,并支持通过 typedef 自定义派生类型。数据类型决定了节点可接受的值范围与格式。
| 类别 | 内置类型 | 说明 | 示例 |
|---|---|---|---|
| 基础类型 | int8 / int16 / int32 / int64 |
有符号整数,范围固定 | type int32; |
| 基础类型 | uint8 / uint16 / uint32 / uint64 |
无符号整数 | type uint16 { range 0..4095; } |
| 字符串 | string |
UTF-8 文本,可加长度限制 | type string { length 1..255; } |
| 布尔 | boolean |
true / false | type boolean; default false; |
| 枚举 | enumeration |
预定义命名值列表 | enum up; enum down; |
| 二进制 | binary |
Base64 编码的二进制数据 | type binary; |
| 特殊类型 | empty |
无值标记,仅表示存在 | type empty; |
| 派生类型 | typedef |
基于内置类型自定义 | typedef vlan-id { type uint16 { range 1..4094; } } |
自定义类型示例:
typedef ipv4-address {
type string {
pattern '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}';
}
description "IPv4 地址格式";
}
typedef admin-status {
type enumeration {
enum up;
enum down;
enum testing;
}
default up;
}
4.4 容器(Container)与列表(List)
容器和列表是 YANG 中组织数据层次的核心结构。容器用于将相关叶子节点分组,列表用于表示可重复的条目集合。
| 结构 | 关键字 | 是否可重复 | 唯一标识 | 典型用途 |
|---|---|---|---|---|
| 容器 | container |
否(单实例) | 无 | 分组配置参数,如系统信息、全局设置 |
| 列表 | list |
是(多实例) | key 语句定义 |
接口列表、路由条目、VLAN 集合 |
| 叶子列表 | leaf-list |
是(多值) | 无(有序集合) | DNS 服务器列表、允许的 VLAN 列表 |
关键约束:列表必须通过
key 语句指定至少一个叶子节点作为唯一键。键值在列表实例中不可重复。如果列表不需要键(如状态数据),可使用 key 语句但留空,但实践中极少使用。
4.5 基线核验中的 YANG 应用
在自动化基线核验场景中,YANG 模型用于:
- 定义期望基线:将设备配置的期望值建模为 YANG 容器/列表结构,存储为 JSON/XML 模板。
- 解析设备状态:通过 NETCONF
<get>或 RESTCONF GET 获取设备实际运行数据,YANG 模型提供解析路径。 - 差异对比:将实际数据与基线模板按 YANG 结构逐节点对比,自动标记偏离项。
- 约束校验:利用 YANG 的
must、when、range等约束语句,在数据写入前验证合规性。
自动化建议:在基线核验脚本中,优先使用
pyang 或 yangson 库加载 YANG 模型,将设备返回的 XML/JSON 数据绑定到模型实例,再通过 Python 字典对比实现基线校验。避免手动解析原始 XML 字符串。