第314篇:OpenConfig 与 IETF 标准模型
关键词:OpenConfig、IETF YANG、标准模型、接口模型、路由模型、多厂商兼容、模型映射
一、引言
前几篇介绍了 NETCONF 和 RESTCONF 这两种协议如何将 YANG 模型作为操作蓝本。然而,YANG 模型本身需要有人来编写——谁来定义这些模型?不同厂商对同一个网络功能(如接口、路由、VLAN)的模型定义是否一致?
这就是 OpenConfig 和 IETF YANG 模型存在的意义:它们提供跨厂商的统一数据模型,使得同一份配置脚本可以在不同品牌的设备上运行。
二、核心概念
2.1 IETF YANG 模型体系
IETF(互联网工程任务组)通过多个工作组定义了覆盖网络核心功能的 YANG 模型:

| IETF 模型 | RFC | 覆盖范围 |
|---|---|---|
| ietf-interfaces | RFC 8343 | 接口基本属性(名称、描述、启用状态、类型) |
| ietf-ip | RFC 8344 | IP 地址配置(IPv4/IPv6 地址、前缀、主机路由) |
| ietf-routing | RFC 8294 | 路由协议实例管理 |
| ietf-bgp | RFC 8349 | BGP 配置、会话状态、地址族 |
| ietf-ospf | 草案阶段 | OSPF 配置与状态 |
| ietf-yang-types | RFC 6021 | 公共 YANG 类型(mac-address、dotted-quad 等) |
| ietf-inet-types | RFC 6991 | 网络类型(ip-address、ipv4-prefix、domain-name 等) |
2.2 OpenConfig 项目概述
OpenConfig 是一个开源的 YANG 模型项目,最初由 Google、Facebook 等互联网企业发起,后由开放网络基金会(ONF)维护。其核心设计理念是:
- 多厂商兼容:模型基于多家设备厂商的共同能力定义,而非单一厂商特性
- 功能优先:以网络功能为组织维度(如 interfaces、routing、platform),而非 CLI 命令层次
- 配置与状态分离:明确区分可写配置数据和只读状态数据
- 向后兼容:模型演进时保持向后兼容,已有自动化脚本无需修改

2.3 OpenConfig 与 IETF 模型对比
| 维度 | OpenConfig | IETF |
|---|---|---|
| 发起方 | Google/Facebook 等互联网企业 | IETF 标准工作组 |
| 设计目标 | 多厂商通用、功能覆盖全面 | 标准化、RFC 发布 |
| 命名风格 | openconfig-interfaces |
ietf-interfaces |
| 接口标识 | 支持别名(alias)、名称、索引 | 仅支持名称 |
| 子接口支持 | 原生支持子接口 | 通过 if-index + sub-interface 扩展 |
| 路由模型 | 统一路由模型(含 BGP/OSPF/IS-IS/Static) | 分散为多个独立模型 |
| 平台信息 | 详细的硬件平台模型(槽位、线卡、端口) | 较简略 |
| 成熟度 | 广泛部署,实际驱动 | 标准发布,渐进式采纳 |
| 许可证 | Apache 2.0 | IETF Trust |
2.4 模型的层次关系

三、技术细节
3.1 ietf-interfaces 模型详解
ietf-interfaces(RFC 8343)是最基础的接口模型:
module ietf-interfaces {
namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces";
prefix "if";
import ietf-yang-types { prefix "yang"; }
import ietf-inet-types { prefix "inet"; }
organization "IETF NETMOD (Network Modeling) Working Group";
contact "IETF NETMOD Working Group";
description "Interface management model";
revision 2018-02-22 {
description "RFC 8343";
}
// 接口列表
list interface {
key "name";
leaf name {
type string;
description "接口名称,作为唯一标识";
}
leaf description {
type string;
description "接口描述(管理用途)";
}
leaf type {
type identityref {
base "iana-if-type:interfaceType";
}
mandatory true;
description "接口类型(如 ethernetCsmacd)";
}
leaf enabled {
type boolean;
default true;
description "接口管理状态(true=启用)";
}
leaf link-up-down-trap-enable {
type boolean;
default true;
}
leaf admin-status {
type enumeration {
enum up;
enum down;
enum testing;
}
config false;
description "管理状态(只读)";
}
leaf oper-status {
type enumeration {
enum up;
enum down;
enum testing;
enum unknown;
enum dormant;
enum not-present;
enum lower-layer-down;
}
config false;
description "运行状态(只读)";
}
leaf if-index {
type int32 {
range "1..2147483647";
}
config false;
}
// 统计计数器
container statistics {
config false;
leaf in-octets {
type yang:counter32;
}
leaf in-unicast-pkts {
type yang:counter32;
}
leaf in-discards {
type yang:counter32;
}
leaf in-errors {
type yang:counter32;
}
leaf out-octets {
type yang:counter32;
}
leaf out-unicast-pkts {
type yang:counter32;
}
leaf out-discards {
type yang:counter32;
}
leaf out-errors {
type yang:counter32;
}
}
}
// 接口统计(全局)
container interfaces-state {
config false;
list interface {
key "name";
leaf name {
type string;
}
leaf if-index {
type int32;
}
leaf type {
type identityref {
base "iana-if-type:interfaceType";
}
}
leaf oper-status {
type enumeration {
enum up;
enum down;
enum testing;
enum unknown;
}
}
leaf in-octets {
type yang:counter64;
}
leaf out-octets {
type yang:counter64;
}
container statistics {
leaf in-octets {
type yang:counter64;
}
leaf out-octets {
type yang:counter64;
}
leaf in-errors {
type yang:counter64;
}
leaf out-errors {
type yang:counter64;
}
}
}
}
}
3.2 OpenConfig Interfaces 模型详解
OpenConfig 的接口模型比 IETF 更丰富,支持子接口、MTU、子速率等高级功能:
module openconfig-interfaces {
namespace "http://openconfig.net/yang/interfaces";
prefix "oc-if";
import openconfig-if-aggregate { prefix "oc-ifagg"; }
import openconfig-if-ethernet { prefix "oc-ifeth"; }
import openconfig-types { prefix "oc-types"; }
import ietf-yang-types { prefix "yang"; }
import ietf-inet-types { prefix "inet"; }
organization "OpenConfig working group";
contact "OpenConfig";
description "Model for interface management";
// 主接口容器
container interfaces {
list interface {
key "name";
leaf name {
type string;
description "接口名称";
}
leaf config {
type leafref {
path "config/name";
}
}
// 配置数据
container config {
leaf name {
type string;
}
leaf description {
type string;
}
leaf type {
type identityref {
base "oc-if-types:IF_TYPE";
}
}
leaf enabled {
type boolean;
default true;
}
leaf loopback-mode {
type boolean;
}
leaf mtu {
type uint16;
description "最大传输单元";
}
}
// 状态数据
container state {
leaf name {
type string;
config false;
}
leaf oper-status {
type enumeration {
enum UP;
enum DOWN;
enum TESTING;
enum UNKNOWN;
enum DORMANT;
}
config false;
}
leaf phys-address {
type yang:mac-address;
config false;
description "物理 MAC 地址";
}
leaf highest-speed {
type oc-types:BPS;
config false;
}
leaf mtu {
type uint16;
config false;
}
// 子接口列表
list subinterface {
key "index";
leaf index {
type uint32;
description "子接口索引号";
}
container config {
leaf index {
type uint32;
}
leaf description {
type string;
}
leaf enabled {
type boolean;
}
}
container state {
leaf index {
type uint32;
config false;
}
leaf oper-status {
type enumeration {
enum UP;
enum DOWN;
}
config false;
}
}
// 子接口的以太网配置
container ethernet {
container config {
leaf min-mac-limit {
type uint16;
}
leaf max-mac-limit {
type uint16;
}
}
}
// 子接口的 IP 配置
container ipv4 {
list address {
key "ip";
leaf ip {
type inet:ipv4-address;
}
container config {
leaf ip {
type inet:ipv4-address;
}
leaf prefix-length {
type union {
type inet:ipv4-prefix-length;
type yang:dotted-quad;
}
}
}
}
}
}
}
}
}
}
3.3 接口配置:IETF vs OpenConfig JSON 对比
同一接口配置用两种模型表示:
{
"ietf_comparison": {
"ietf_interfaces": {
"ietf-interfaces:interface": {
"name": "GigabitEthernet1/0/1",
"description": "Uplink-to-Core",
"type": "iana-if-type:ethernetCsmacd",
"enabled": true,
"ietf-ip:ipv4": {
"address": [
{
"ip": "10.2.2.1",
"netmask": "/30"
}
]
}
}
},
"openconfig_interfaces": {
"openconfig-interfaces:interface": {
"config": {
"name": "GigabitEthernet1/0/1",
"description": "Uplink-to-Core",
"type": "ETHernetCsmacd",
"enabled": true,
"mtu": 9000
},
"state": {
"name": "GigabitEthernet1/0/1",
"oper-status": "UP",
"phys-address": "00:11:22:33:44:55"
},
"subinterfaces": {
"subinterface": [
{
"index": 0,
"config": {
"index": 0,
"description": "Main-subinterface"
},
"ipv4": {
"addresses": {
"address": [
{
"config": {
"ip": "10.2.2.1",
"prefix-length": 30
}
}
]
}
}
}
]
}
}
}
}
}
| 对比维度 | IETF 模型 | OpenConfig 模型 |
|---|---|---|
| 配置/状态组织 | 同一节点内混合,用 config false 区分 |
明确分离 config 和 state 容器 |
| 子接口支持 | 不支持(需厂商扩展) | 原生支持 subinterface 列表 |
| MTU | 不在核心模型中 | 在 config/mtu 中定义 |
| MAC 地址 | 无 | state/phys-address |
| 接口速率 | 无 | state/highest-speed |
| 命名空间 | urn:ietf:params:xml:ns:yang:ietf-interfaces |
http://openconfig.net/yang/interfaces |
3.4 OpenConfig Routing 模型
OpenConfig 的路由模型提供了统一的路由协议管理框架:
module openconfig-routing-policy {
namespace "http://openconfig.net/yang/policy";
prefix "oc-pol";
organization "OpenConfig working group";
description "Routing policy model";
// 策略定义
container routing-policy {
list policy-definition {
key "name";
leaf name {
type string;
description "策略名称";
}
// 策略条目列表
list policy-statements {
leaf statement-id {
type string;
}
// 匹配条件
container conditions {
container match {
// 匹配路由协议
leaf route-type {
type enumeration {
enum DIRECT;
enum STATIC;
enum CONNECTED;
enum BGP;
enum OSPF;
enum ISIS;
}
}
// 匹配前缀
container address-prefixes {
list address-prefix {
key "prefix-length";
leaf prefix-length {
type uint8;
}
leaf prefix {
type string;
}
}
}
}
}
// 策略动作
container actions {
leaf policy-result {
type enumeration {
enum ACCEPT_ROUTE;
enum REJECT_ROUTE;
}
}
// 设置路由属性
container route-modifications {
leaf community {
type oc-types:COMMUNITY_TYPE;
}
leaf local-preference {
type uint32;
}
leaf metric {
type uint32;
}
}
}
}
}
}
}
3.5 模型选择与兼容性策略

| 场景 | 推荐模型 | 理由 |
|---|---|---|
| 单一华为设备 | 华为扩展模型 | 功能覆盖最全,支持所有华为特性 |
| 多厂商设备混合 | OpenConfig | 多厂商共识模型,功能比 IETF 丰富 |
| 最大兼容性要求 | IETF 标准模型 | 所有 NETCONF/RESTCONF 设备均支持 |
| 子接口管理 | OpenConfig | IETF 不支持子接口 |
| 硬件平台信息 | OpenConfig | 提供槽位、线卡、端口详细模型 |
| 路由策略 | OpenConfig | 统一策略模型,比 IETF 完善 |
四、实战配置/案例分析
4.1 案例一:用 IETF 模型跨厂商管理接口
# scripts/ietf_multi_vendor.py
from ncclient import manager
import xml.etree.ElementTree as ET
# IETF interfaces 模型在所有厂商间通用
IETF_INTERFACE_FILTER = """
<filter type="subtree">
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"/>
</filter>
"""
def collect_interfaces_iETF(device):
"""使用 IETF 标准模型采集接口(跨厂商通用)"""
with manager.connect(
host=device["host"],
port=830,
username=device["username"],
password=device["password"],
hostkey_verify=False,
device_params={"name": device.get("vendor", "huawei")},
timeout=30
) as m:
reply = m.get_config(source="running", filter=IETF_INTERFACE_FILTER)
return ET.tostring(reply.data_element, pretty_print=True).decode()
# 多厂商设备
devices = [
{"host": "10.1.1.1", "username": "admin", "password": "HuaWei@123", "vendor": "huawei"},
{"host": "10.1.1.2", "username": "admin", "password": "Juniper1", "vendor": "juniper"},
{"host": "10.1.1.3", "username": "admin", "password": "Cisco123", "vendor": "cisco"},
]
for device in devices:
try:
config = collect_interfaces_iETF(device)
print(f"✓ {device['host']} ({device['vendor']}): 采集成功, {len(config)} bytes")
except Exception as e:
print(f"✗ {device['host']}: {e}")
4.2 案例二:OpenConfig 模型配置子接口
# scripts/openconfig_subinterface.py
import requests
import json
BASE_URL = "https://10.1.1.1:443/restconf/data"
HEADERS = {
"Accept": "application/yang-data+json",
"Content-Type": "application/yang-data+json",
}
def configure_openconfig_subinterface(session, interface_name, subindex,
ip_address, prefix_length):
"""使用 OpenConfig 模型配置子接口"""
encoded = interface_name.replace("/", "%2F")
url = (f"{BASE_URL}/openconfig-interfaces:interfaces/interface"
f"={encoded}/subinterfaces/subinterface={subindex}")
subinterface_config = {
"openconfig-interfaces:subinterface": {
"config": {
"index": subindex,
"description": f"Subinterface-{subindex}",
"enabled": True
},
"ipv4": {
"addresses": {
"address": [
{
"config": {
"ip": ip_address,
"prefix-length": prefix_length
}
}
]
}
}
}
}
resp = session.put(url, headers=HEADERS, json=subinterface_config)
return resp.status_code in (200, 204)
# 使用示例
subinterfaces = [
(10, "10.10.10.1", 30),
(20, "10.20.20.1", 30),
(30, "10.30.30.1", 30),
]
for subindex, ip, prefix in subinterfaces:
success = configure_openconfig_subinterface(
SESSION, "GigabitEthernet1/0/1", subindex, ip, prefix
)
print(f"{'✓' if success else '✗'} Subinterface {subindex}: {ip}/{prefix}")
4.3 案例三:模型兼容性问题排查
故障场景:同一份自动化脚本在华为设备上运行正常,在 Juniper 设备上失败。
# scripts/model_compatibility_check.py
from ncclient import manager
def check_model_support(m, module_name):
"""检查设备是否支持特定 YANG 模块"""
capabilities = m.server_capabilities
supported = []
for cap in capabilities:
# 检查 model capability
if "yang:" in cap:
parts = cap.split(";")
for part in parts:
if part.startswith("module="):
module = part.split("=")[1]
if module_name.lower() in module.lower():
supported.append(cap)
return supported
def test_ietf_vs_openconfig():
"""对比测试 IETF 和 OpenConfig 模型支持"""
results = {}
for vendor, host in [("huawei", "10.1.1.1"), ("juniper", "10.1.1.2")]:
try:
with manager.connect(
host=host, port=830,
username="admin", password="Pass123",
hostkey_verify=False,
device_params={"name": vendor}
) as m:
# 检查 IETF interfaces
ietf_caps = check_model_support(m, "ietf-interfaces")
# 检查 OpenConfig interfaces
oc_caps = check_model_support(m, "openconfig-interfaces")
results[vendor] = {
"ietf_interfaces": bool(ietf_caps),
"openconfig_interfaces": bool(oc_caps),
"ietf_capabilities": ietf_caps,
"oc_capabilities": oc_caps,
}
except Exception as e:
results[vendor] = {"error": str(e)}
return results
compatibility = test_ietf_vs_openconfig()
for vendor, result in compatibility.items():
print(f"\n{vendor}:")
if "error" in result:
print(f" 连接失败: {result['error']}")
else:
print(f" IETF interfaces: {'支持' if result['ietf_interfaces'] else '不支持'}")
print(f" OpenConfig interfaces: {'支持' if result['openconfig_interfaces'] else '不支持'}")
故障根因:
1. Juniper 设备可能不支持 OpenConfig 模型,仅支持 IETF 标准模型和厂商自有模型
2. 接口类型标识在不同模型中名称不同(iana-if-type:ethernetCsmacd vs ETHernetCsmacd)
3. 华为设备的 NETCONF 实现可能在某些 IETF 模型上存在差异
解决方案: - 在脚本启动时先探测设备支持的 YANG 模块 - 根据探测结果动态选择使用 IETF 或 OpenConfig 模型 - 为不同模型编写适配层(adapter),将统一配置转换为对应模型的格式
四(续)、高级主题
4.4 OpenConfig 模型版本管理与向后兼容
OpenConfig 模型通过 revision 日期跟踪版本演进:
module openconfig-interfaces {
yang-version 1.1;
namespace "http://openconfig.net/yang/interfaces";
prefix "oc-if";
organization "OpenConfig working group";
contact "openconfig@openconfig.net";
// 每个 revision 代表一次正式发布
revision 2023-11-02 {
description "Latest stable release";
reference "https://github.com/openconfig/public/releases/tag/interfaces-latest";
}
revision 2020-01-24 {
description "Added subinterface support";
}
revision 2017-02-20 {
description "Initial release";
}
}
版本兼容性策略:
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 最小版本约束 | 脚本检查设备支持的 revision,低于最低版本则跳过 | 多版本设备混布 |
| 功能探测 | 尝试访问特定节点,404 表示不支持 | 渐进式功能升级 |
| 适配层抽象 | 封装不同版本的 API 差异,对外暴露统一接口 | 跨版本自动化平台 |
# scripts/model_version_check.py
from ncclient import manager
MIN_REVISIONS = {
"openconfig-interfaces": "2020-01-24",
"openconfig-routing-policy": "2019-04-15",
}
def check_model_versions(device):
"""检查设备支持的模型版本"""
with manager.connect(
host=device["host"], port=830,
username=device["username"], password=device["password"],
hostkey_verify=False,
device_params={"name": device["vendor"]}
) as m:
results = {}
for module_name, min_rev in MIN_REVISIONS.items():
for cap in m.server_capabilities:
if module_name in str(cap):
# 提取 revision 日期
rev_match = re.search(r'revision;\s*([\d-]+)', str(cap))
if rev_match:
actual_rev = rev_match.group(1)
supported = actual_rev >= min_rev
results[module_name] = {
"required": min_rev,
"actual": actual_rev,
"supported": supported
}
return results
4.5 YANG 模型开发最佳实践
当标准模型不满足需求时,需要自行扩展 YANG 模型:
// 自定义扩展:华为设备光模块详细信息
module huawei-transceiver-ext {
yang-version 1.1;
namespace "urn:huawei:params:yang:huawei-transceiver-ext";
prefix "hw-tx";
import openconfig-interfaces { prefix oc-if; }
import ietf-yang-types { prefix yang; }
// 通过 augment 扩展 OpenConfig 接口模型
augment "/oc-if:interfaces/oc-if:interface" {
case openconfig-if-ethernet:
container huawei-transceiver {
description "华为设备光模块详细信息";
leaf serial-number {
type string;
description "光模块序列号";
}
leaf manufacturer {
type string;
description "光模块厂商";
}
leaf part-number {
type string;
description "光模块料号";
}
container diagnostic {
leaf tx-power {
type decimal64 { fraction-digits 2; }
units "dBm";
description "发送光功率";
}
leaf rx-power {
type decimal64 { fraction-digits 2; }
units "dBm";
description "接收光功率";
}
leaf temperature {
type decimal64 { fraction-digits 1; }
units "Celsius";
description "光模块温度";
}
leaf voltage {
type decimal64 { fraction-digits 2; }
units "V";
description "供电电压";
}
leaf bias-current {
type decimal64 { fraction-digits 2; }
units "mA";
description "偏置电流";
}
}
}
}
}
}
4.6 模型驱动配置生成器
# scripts/model_config_generator.py
import json
class ModelDrivenConfigGenerator:
"""基于 YANG 模型的配置生成器"""
def __init__(self, model="openconfig"):
self.model = model
def generate_interface_config(self, interface_name, **kwargs):
"""根据模型类型生成接口配置"""
if self.model == "openconfig":
return {
"openconfig-interfaces:interface": {
"config": {
"name": interface_name,
"description": kwargs.get("description", ""),
"type": "iana-if-type:ethernetCsmacd",
"enabled": kwargs.get("enabled", True),
},
"subinterfaces": {
"subinterface": [{
"config": {
"index": kwargs.get("subindex", 0),
"description": kwargs.get("sub_desc", ""),
},
"ipv4": {
"addresses": {
"address": [{
"config": {
"ip": kwargs.get("ip", ""),
"prefix-length": kwargs.get("prefix", 24),
}
}]
}
}
}]
}
}
}
elif self.model == "ietf":
return {
"ietf-interfaces:interface": {
"name": interface_name,
"description": kwargs.get("description", ""),
"type": "iana-if-type:ethernetCsmacd",
"enabled": kwargs.get("enabled", True),
"ietf-ip:ipv4": {
"address": [{
"ip": kwargs.get("ip", ""),
"netmask": f"/{kwargs.get('prefix', 24)}"
}]
}
}
}
# 使用
gen = ModelDrivenConfigGenerator(model="openconfig")
config = gen.generate_interface_config(
"GigabitEthernet1/0/1",
description="To-CoreRtr-Uplink",
ip="10.1.1.1",
prefix=30
)
print(json.dumps(config, indent=2))
五、总结
| 模型体系 | 适用场景 | 优势 | 局限 |
|---|---|---|---|
| IETF 标准模型 | 跨厂商最大兼容性 | 所有 NETCONF 设备支持,标准权威 | 功能覆盖有限,缺少子接口/MTU 等 |
| OpenConfig 模型 | 多厂商功能丰富的场景 | 功能全面,厂商共识,社区活跃 | 部分厂商实现不完全,版本差异 |
| 厂商扩展模型 | 单一厂商深度功能 | 支持所有设备特性 | 锁定厂商,无法跨设备复用 |
| 最佳实践 | 说明 |
|---|---|
| 优先标准模型 | 新项目优先使用 IETF 或 OpenConfig,避免厂商锁定 |
| 能力探测 | 脚本启动时探测设备支持的 YANG 模块 |
| 适配层设计 | 编写统一 API,内部适配不同模型 |
| 模型版本管理 | 跟踪模型 revision,确保自动化脚本与模型版本匹配 |
| 测试验证 | 在目标设备实际验证模型节点是否可用 |
思考题
- 为什么 OpenConfig 模型将配置数据和状态数据分离到
config和state两个容器,而 IETF 模型混在一起? - 在一个同时运行华为、Juniper、Cisco 的网络中,选择 OpenConfig 还是 IETF 模型?为什么?
- YANG 模型中的
identityref类型有什么作用?为什么接口类型不用string而用identityref?
下篇预告:第315篇:gNMI/gNOI:谷歌开源的网络管理协议