注:本文为 "网管协议" 相关文章合辑。
网管协议 - SNMP,NETCONF,RESTCONF
posted @ 2021-02-22 21:13 来份锅包肉
传统 CLI 配置网络设备存在的挑战,网管协议出现的背景
随着 5G 的兴起,SDN、NFV 等概念被频繁提及。要更好地理解这些概念,网络协议是必不可少的一环。
以 SDN 为例,其全称为 Software Defined Networking(软件定义网络)。传统网络采用分布式架构,控制平面和转发平面均位于同一台设备上,在运维及灵活性方面存在诸多挑战。
SDN 的出现将控制平面和转发平面解耦,并将所有设备统一管理,使网络具备了可编程能力。从面向服务的角度出发,可根据业务需求实时动态地调整设备的配置或状态,从而大幅降低了管理难度。
那么,NETCONF、RESTCONF 等协议又起到了怎样的作用呢?
这需要从 SDN 架构说起,SDN 主要包含三个角色:SDN 应用、SDN 控制器以及网络设备。

SDN 应用通常通过 HTTP 方式调用 SDN 控制器暴露的接口,而 SDN 控制器则通过 NETCONF、RESTCONF 等类似协议与设备进行交互,实现业务的下发。
由此可见,NETCONF 等类似协议起到了与设备直接交互的作用。
此外,DEVOPS 概念的流行也强调从传统人工 CLI 配置向自动化的网络配置过渡,NETCONF 等类似协议使得这些自动化操作成为可能,例如目前的 ANSIBLE、Python 的各种类库等。
以下是网管协议的实际用例,其涵盖的范围已经非常广泛:

下面从传统 CLI 面临的挑战开始,详细了解这些发挥着重要作用的协议。
传统命令操作带来的主要挑战
采用传统 CLI 配置方式主要存在以下挑战:

在兼容性方面,网络工程师肯定深有体会。
以配置静态路由为例,Cisco 设备的命令如下:
c
Router(config)#ip route 0.0.0.0 0.0.0.0 10.10.10.1
而对于华为和华三设备来说:
c
Router(config)#ip route-static 0.0.0.0 0.0.0.0 10.10.10.1
有时不仅不同厂商之间的命令不同,甚至同一厂商不同型号之间的命令也不相同。
例如,思科针对不同场景区分了不同的网络软件系统:
- 针对企业的 IOS
- 针对运营商的 IOS-XR
- 针对数据中心的 NX-OS
- 以及面向下一代的 IOS-XE,将数据层面和控制解耦,底层支持 Linux
在出错率方面,人工配置远不如机器配置准确且迅速。
当前的网络在规模和需求上与以往大不相同,例如在实时性方面,运营商需要根据业务需求动态调整策略,如 EVPN、L3VPN、L2TP,传统 CLI 手工配置根本无法满足,也无法做到维护管理。而目前的常用解决方案是利用一些现成的 SDN Controller 进行实时调整,如 Cisco 的 NSO。
在数据采集方面,传统人工定时登录设备查看系统日志、分析情况的方式已无法适用,其在故障响应上也存在先天不足,如收集效率低、数据利用率低或延迟高等问题。
从商业成本角度考虑,人工维护方案也是一笔较高的支出。
对于工程师而言,需要不断学习不同厂商的配置命令,学习成本很高,但意义不大。
通常来说,网络工程师在开始一个项目前,会进行以下四个部分的操作:
- 了解用户需求
- 针对用户需求,确定相应的具体方案
- 根据用户方案,查找并学习对应设备的配置命令
- 最后申请割接窗口,准备回滚方案并实施
其中第三步是一个比较耗时但意义不大的过程,因为在集中学习不同厂商的设备命令,但从业务角度考虑,明明解决的都是同一个问题。
在发现 CLI 管理设备的方式出现瓶颈后,并非立即过渡到当前流行的网络自动化配置方式,而是先推出了一个名为 Simple Network Management Protocol
(SNMP)的应用层协议,甚至在当前的一些现网中,依然被使用。
SNMP
SNMP 的出现主要旨在解决以下两个问题:
- 设备信息的采集
- 使用 GUI 替代 CLI 的方式进行设备配置下发
但由于其读多写少的特点,目前被广泛用于设备信息的监控和采集。
SNMP 目前共有三个版本:
- SNMP V1,第一个版本。在管理设备时,采用明文方式,有
read-only
、read-write
、trap
三种与设备通信的方式。 - SNMP V2,主要改进了性能、安全性和设备交流的方式。
- SNMP V3,主要优化了安全性,增加了一些更强的认证流程。
SNMP 原理
SNMP 整体架构类似于 Client/Server,其主要工作组件有三个:
- SNMP Manager:主要用于管理网络中的多个设备,对其进行读写操作,类似于 Server。
- SNMP Agent:运行在网络设备上,通常需要手动开启。作为 SNMP 代理,在收到 SNMP Manager 发出的请求后,对请求内容进行解析,然后对设备进行配置,并将配置结果作为 Response 回复给 Manager。
- SNMP MIB:MIB(Management Information Base)全称为信息管理库。可以将其理解为用于交互的一种数据模型,也就是交互的规则。MIB 同样存在于网络设备中,定义和描述了如何管理设备上的资源,Manager 和 Agent 之间的交流信息即为 MIB 的内容。

可以看到,一个 Manager 可以管理网络中的多个设备,而每台设备上运行着 SNMP Agent 用于与 Manager 信息交互,交流内容需要符合 MIB 的规范。
看到这里,可能对 MIB 这个概念还比较模糊。下面从设计角度来分析为什么要有 MIB 这个东西。
这里想要实现的是通过 Manager 去管理网络上的 Agent(其实就是管理设备)。那么如何管理呢?例如,Manager 想要获取 Agent1 的 GigabitEthernet0/0/0/1 的 IP 地址。
这时就需要在 Agent1 上先约定好一个内容,比如当 Agent 接收到 1.1
这个字符串时,就会将接口的信息返回给 Manager。
之后如果 Manager 发送 1.1
就能获取到接口的信息,但发送其他内容,Agent 是无法识别并工作的。MIB 本质上就是确定了如 1.1
这样的一组规则,去规范信息交互的访问方式。
实际上,在 MIB 中还以层级的方式存在着许多这样的对象,将网络设备的资源抽象成形如 1.1
的对象。通过这些对象,Manager 和 Agent 就可以实现很好的交流。
真正的 MIB 类似于下图,而这里形如 1.3.6.1.1.1.2
这样连接起来的字符串称为 ASN,其实就是对应了设备上的各种资源,Manager 和 Agent 也通过它们进行交流。

SNMP 操作
SNMP Manager 和 SNMP Agent 间的交互主要有以下三种类型:
- SNMP Get
- SNMP Set
- SNMP Notifications
SNMP Get:主要用于检索设备的信息,Get 又分为以下三种类型:
- GET:从 SNMP Agent 获取固定的对象。
- GETNEXT:检索当前对象的后一个对象。由于 MIB 本身具有层级的树形结构,因此存在后继对象。
- GETBULK:获取一组固定的对象。
SNMP Set:主要用于修改 MIB 中的对象,进而修改设备的配置。
SNMP Notifications:是 SNMP 的主要特性之一。之前的 GET 和 SET 属于拉的操作,而 SNMP Notifications 则相反,类似于推的操作,可以由 Agent 发起,将一些信息 push 到 SNMP Manager 上,类似于 Web Socket。主要用于通知如认证失败、重启、断开连接等事件。
Notifications 主要有两种形式:Traps 和 Informs。两者之间的主要区别在于可靠性。Agent 在产生 Informs 给 Manager 后,如果发送失败,会重新发送。Manager 收到后,需要回复确认给 Agent。
而 Traps 则不同,无论消息发送是否成功,Manager 都不需要回复。


SNMP 缺点
虽然 SNMP 的出现一定程度上解决了网络设备的管理问题,但面对现代大规模网络时,依然存在诸多挑战:
- 性能不足,在下发和读取配置时,采用依次读取的方式,效率较低。
- 下发能力不足,支持写 MIB 的对象相对于读较少。
- 不支持事务机制,在配置下发失败时,无法回滚。
- 拓展性差,提供给外部的接口较少。
- 模型兼容性差,MIB 库混乱,无法适配所有厂商,导致定义各种私有 MIB 库。
针对这些问题,2006 年由 IETF 领导并开发出了一个新的协议 - NETCONF(网络管理协议)。与 SNMP 不同,NETCONF 基于 RPC 的方式,天生就能很好地支持事务回滚等操作,从而更好地处理复杂网络的各种需求。
NETCONF
NETCONF 协议提供了一种更简单的方式来管理("查询、配置、修改、删除")设备,类似于数据库操作中的 DML。同时开放了 API 接口,当想要对设备进行操作时,直接通过调用 API 即可。
对于支持 NETCONF 的设备来说,至少能开启一个或多个 session。并且在每个 session 中应用的配置更改,都可以被全局的 session 监听到。这使得一个或多个 Manager(Client)操作同一个设备(Agent)成为可能。
与 SNMP 相比,NETCONF 具有以下优势:
- 基于 RPC,增加了事务支持。
- 优化查询功能,增加了过滤查询方式。
- 拓展性强,在其协议内部分为 4 层,各层之间相互独立。
- 更好地将配置和状态数据解耦,并区分状态数据(candidate、running、startup)。
- 易于使用,结合提供的 API,实现可编程性的网络操作。
- 安全性更好,在传输层可选用 SSH、TLS 协议等。
NETCONF 采用 C/S 架构,通过 RPC 在 Client 和 Server 间交流。Client 可以是 Python 脚本或应用,Server 一般指的是网络设备。在具体实现上有三个组件:
- NETCONF Agent:运行在网络设备上,用于接收和处理 RPC 请求。还可主动将一些告警事件通知客户端。
- NETCONF 客户端:利用 NETCONF 协议对网络设备进行管理以及接收 Agent 发出的告警通知。
- Datastore:在 NETCONF 中,区分了多个不同类型的 Datastore,这些 Datastore 保存着不同状态下的设备信息。
关于 Datastore,可以将其理解为一个可以获取和存储信息的概念。在具体实现上,可以是文件、数据库、内存等。
在 NETCONF 中常用到三类 Datastore:
- Startup Configuration Datastore:保存了设备启动时加载的配置信息。
- Candidate Configuration Datastore:保存了想要运行的配置信息,修改该数据库时,并不会影响设备的真实配置。
- Running Configuration Datastore:保存了当前设备上正在生效的配置,修改时会影响真实的设备。
此外,提到 Datastore 就必须提到一种数据模型语言 - YANG。Datastore 中就是以 YANG 的形式来约束配置的数据。
YANG 的出现结合 NETCONF 和 RESTCONF 等协议,为自动化、可编程化的网络提供了强大的支持。YANG 的本质和 SNMP 中 MIB ASN 一样,作用都是以一种方式来约束数据。关于 YANG 后续会单独写一篇文章介绍。
NETCONF 协议架构

NETCONF 分为 4 层,各层之间相互独立。
-
内容层 :
这一层包含了以 XML 或 JSON 格式的配置数据,也就是对设备进行管理的具体内容(由 XSD 或 YANG 约束生成)。
-
操作层 :
定义了 Client 和 Server 交互时的一系列操作方法,用于获取或修改配置数据。
-
消息层 :
为编码数据时提供了一种 RPC 和通知的机制:
scss* RPC invocations(<rpc> messages) * RPC results(<rpc-reply> messages) * event notifications(<notification> messages)
-
传输层 :
NETCONF 使用 SSH 或 TLS 协议,保证数据在 Client 和 Server 传输的安全性。
NETCONF 交互

对于 Manager 和 Agent 来说,Session 建立会经历以下过程:
- Manager 请求 NETCONF 中 SSH 子系统建立连接。
- Agent 回复 Hello 消息,包含其本身支持的特性和能力。
- Manager 告知 Agent 自己所支持的特性和能力。
- Manager 开始发送 RPC 操作请求。
- Agent 回复 RPC 请求操作结果。
具体来看 NETCONF 中消息的报文结构,以修改接口配置为例:

Manager 请求变更接口配置:
xml
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<running/>
</target>
<config>
<top xmlns="http://example.com/schema/1.2/config ">
<interface>
<name>Ethernet0/0</name>
<mtu>1500</mtu>
</interface>
</top>
</config>
</edit-config>
</rpc>
Agent 回复结果:
xml
<rpc-reply message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<ok/>
</rpc-reply>
可以看到,NETCONF 使用 XML 作为数据传输的格式。
第一行的 <rpc>
标签表明该请求是 RPC 请求,message-id
属性由 client/manager 确定。Agent 在回复结果时,会带上 message-id
,用于表示该操作的结果。
urn:ietf:
属性表示 XML 中的命令空间,base:1.0
表示当前 NETCONF 的版本。
第二行 <edit-config>
指定执行 RPC 操作的内容为修改配置。
之后 <config>
中包裹的内容就是想要下发的配置内容,修改 mtu 为 1500。
但这里还有一个疑问,在提到 NETCONF 时,总提到一种叫 YANG 的语言,那么它们之间的关系是什么?
在组装修改设备配置 Payload 时,这里也没有用到 YANG?
其实,YANG 早已用到了。为什么 <interface>
中可以包含 <name>
和 <mtu>
属性,而不是把 mtu
放在和 <interface>
同级?
原因就在于上面的格式,都是按照 YANG 的约束而来。
在设备中,存在着许多的 YANG Module,这些 Module 都是由 YANG 语言编写的文件。当 Agent 接收到 RPC 请求时,会通过 YANG Module 来校验发来的数据,格式是否合法。
简单来说,可以把 YANG 理解成一份约束文件,里面规定着传来参数的格式,是数组、对象还是其他格式。
至于说为什么 YANG 文件能约束 XML 的文件格式,原因在于 YANG 和 XML 之间是可以相互转换的,甚至 YANG 还可以转换成 JSON。在之后的 RESTCONF 中会提到这一点。
到目前为止,对 NETCONF 已经有了一个大体认识:
NETCONF 的出现是为了弥补像 SNMP 这些协议的不足,更好地满足现在网络的需要,在易用性、拓展性等方面都做出了进一步优化,从而更方便、高效地管理网络。
究其本质,NETCONF 是由多个协议组装而成。数据的产生及校验通过 YANG,数据的格式是 XML,接口的调用通过 RPC,数据的传输通过 SSH。
NETCONF 操作
Server 端 :打开设备 NETCONF
mipsasm
# 打开 netconf
netconf-yang
# 查看 netconf 进程
show platform software yang-management
Client 端 :测试设备 NETCONF
css
ssh admin@IP -p 830 -s netconf
关于 NETCONF 具体实现编程化操作,可以参见 YANG。
RESTCONF
在谈起 RESTCONF 前,想必刚接触这个概念的人都会有这样一个疑问:RESTCONF 和 REST 到底有没有关系?
在回答这个问题前,先来回忆一下什么是 REST,以及 REST 出现的背景。
REST - Representational State Transfer,全称为表现层状态转化,是建立在 HTTP 基础上,对其进行规范的一种架构风格要求。
注意,REST 是一种设计的风格,而不是标准。
其认为,网络中的实体都是以资源的方式存在,但资源存在着多种表现形式,取决于使用者的需要。例如一个用户的信息,可以用 XML、JSON、甚至是 txt 等多种方式表现出来。将不同的网络资源转换成不同的表现形式,就是其表现层的体现。
而状态转移来说,由于 HTTP 本身是无状态的协议,所以资源的状态全都保存在服务端。当对服务端的资源进行操作时,必然存在数据状态的改变。
但由于状态的改变基于表现层,所以称为表现层状态转移。
在具体实现上,URI 定义了访问资源的具体路径,而 HTTP 中 Header 的 Content-Type
和 Accept
决定了表现层的形式。
HTTP 中的 CURD 动作(Create,Put,Get,Delete,patch 等)去改变服务端的资源状态。
例如查询书店具有的图书:
bash
GET http://www.store.com/products
通过 REST 的方式,更合理地实现 WEB 服务之间的交互。
这时再看 RESTCONF,就很好理解了。RESTCONF 是通过 REST 来实现对网络设备管理的协议。其本质和 NETCONF 很像,使用 YANG 进行数据的定义和约束,使用 HTTP 进行交互,使用 NETCONF 中 Datastore 的概念,进行信息的储存。
RESTCONF 架构

图中很好地表示了 RESTCONF 协议的组成,很形象地指出 RESTCONF = NETCONF / YANG + HTTP(s)。
如果拿之前的 NETCONF 协议架构作为对比,RESTCONF 就是将:
- 内容层,同样由 YANG 约束生成。
- RPC 消息层和操作层,换成了 HTTP 的操作层。
- 将 SSH 构成
的传输层,换成了 HTTP(s)的传输方式。
RESTCONF VS NETCONF 交互

图中很好地对比了 RESTCONF 和 NETCONF 的交互过程,都是采用了 C/S 架构,在具体组件上:
NETCONF | RESTCONF | |
---|---|---|
客户端 | NETCONF client | HTTP Client |
配置格式由谁约定 | YANG module / XSD | YANG module |
发送内容格式 | XML | XML/JSON |
交互方式 | RPC | HTTP |
传输协议 | SSH | HTTP(s) |
服务端 | NETCONF server | HTTP server |
对于操作来说,将 RPC 操作换成了 HTTP 操作:

RESTCONF 操作
Server 端 :打开设备 RESTCONF
mipsasm
# 打开 RESTCONF
restconf-yang
# 查看 RESTCONF 进程
show platform software yang-management
Client 端 :
由于已经采用了 REST 风格,可以利用 POSTMAN 等 HTTP 客户端进行测试。
关于 RESTCONF 具体实现编程化操作和其 URL 的使用是非常重要的一部分,但由于其依赖 YANG 这个概念,后续会单独提到,可以参见 YANG 的相关介绍。
总结
这篇文章耗时很久,查阅了大量资料,完成后如释重负。
当然,对网管协议也有了进一步的理解。
下面做一个简单的总结:
传统 CLI 配置方式已经无法满足当代网络可编程化的需要,而且在兼容性、易用性、正确率等方面存在着诸多问题,进而网管协议应运而生。
SNMP 作为推出的第一代协议,在一定程度上解决了设备管理的问题。但由于其读多写少的特点,以及在兼容性、效率和缺乏事务性方面的不足,在现网中,一般用其作为设备配置采集或监控的工具。
为了更好地满足网络的需要,第二代协议 NETCONF 出现。由于 NETCONF 天生 RPC 支持事务的特点,再加上 YANG 解决了多厂商命令兼容性的问题,现被广泛使用在各种网管平台、SDN 控制器中。
随后 HTTP REST 风格的普及,IETF 又推出了 RESTCONF 协议,将 NETCONF 和 HTTP 整合在一起,以更为流行的方式,实现对设备的管理。
数据模型与网络自动化
posted @ 2021-03-04 16:24 来份锅包肉
传统人工 CLI 配置网络的模式,已经不再适用于当代的网络,面临着兼容性、容错率低、效率低下等问题。
在这样的大背景下,各种网管协议应运而生。但这时就产生一个问题,以怎样的格式和内容去传递配置?
YANG 就是为了解决该问题而出现的。在解释 YANG 前,我们先来回忆一下,传统 CLI 是如何下发配置的?
常常是由网络工程师通过 console、Telnet、SSH 等方式登录上设备,然后直接对设备进行配置,这时自然不用考虑怎样传参的问题,只要懂得设备的命令,直接上去敲就可以。
而 CLI 这样的配置,是一种无结构化的数据。
diff
!
interface Bundle-Ether2
!
interface Bundle-Ether780
description evpn-vpws-test
!
interface MgmtEth0/RSP0/CPU0/0
vrf mgmt
ipv4 address 10.124.3.85 255.255.255.0
!
interface MgmtEth0/RSP0/CPU0/1
shutdown
!
interface TenGigE0/0/1/0
shutdown
!
interface TenGigE0/0/1/1
shutdown
!
interface TenGigE0/0/2/0
shutdown
这样无结构的数据对我们人来说是非常友好的,容易理解和阅读。
但由于换成了 NETCONF 这样的网管协议管理设备,这样的数据发挥不出任何优势,甚至无法被机器识别。因为使用 NETCONF 的目的就是为了使用自动化、可编程化的方案代替人工,从而满足当下网络的各种业务场景。
此时配置结构化的数据就成了必然。
于是各个厂商开始对配置进行结构化的约定,在 NETCONF 中,配置使用 XML 表示,进行参数的下发。
例如对接口的 MTU 进行更改:
xml
<rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<running/>
</target>
<config>
<top xmlns="http://example.com/schema/1.2/config ">
<interface>
<name>Ethernet0/0</name>
<mtu>1500</mtu>
</interface>
</top>
</config>
</edit-config>
</rpc>
但此时又有一个问题,就是下发数据的格式和参数是由谁指定呢?例如这里 interface 命名的定义、类型的定义、层级的定义是如何确定的呢?
我怎么知道在下发接口配置时,就下发这样的配置内容呢?
答案在于各个厂商定义了一套约束标准,也可以理解成配置的模板。这些模板对数据进行约束,判断是否是合法的数据。这也就是数据模型的由来。
以 NETCONF 为例,NETCONF 采用 C/S 架构,Client 端在生成配置内容时会参考定义好的数据模型。Server 在接收时,同样会用这些数据模型进行校验。
具体来说,例如针对下发 JSON 格式的配置,通过 JSON Scheme 定义的 JSD 对数据进行约束。

如左图是具体的数据,右图中是对左侧数据具体进行约束的数据模型。例如这里限定了 productName 的类型是字符串,当前对象共有三个属性等。当传入其他不符合 scheme 的数据时,会进行报错。
如果对 JSON-Scheme 感兴趣,可以去官网仔细了解。
对于思科设备来说,这种由 JSON-Scheme 定义的文件叫 JSD,用于约束传入的数据类型。需要注意的是,不同厂商定义的 JSD 内容和格式是不一样的,甚至同一厂商定义的不同类型的 JSD 也不一样。
针对下发的 XML 格式的配置也采用相同的方法,各个厂商通过 XML Scheme 定义 XSD 对数据进行约束。

左面是 xml 格式的数据,右边是 XSD 文件对其进行约束,规定了属性的类型。同样不同厂商编写的 XSD 约束也是不一样的。
虽然通过编写 XSD 和 JSD 的方式解决了如何约束配置数据的问题,但由于不同厂商编写的数据模型没有统一的规范,导致各种各样的 JSD/XSD 出现,学习成本也很高。而且造成很严重的兼容性问题。例如 Cisco 的 JSD 或者 XSD 一定和 HUAWEI 不一样。甚至 Cisco 本身每个团队开发出的 JSD/XSD 的内容也不一样。
为了解决这个问题,由 IETF 主导,开发出了 YANG - Yet Another Next Generation,被现在各个协议广泛使用。
YANG
YANG 的定义
YANG 是一种数据模型语言,用于在 NETCONF 等网络协议中,将想要操作的配置或状态数据进行模型化,用层次化的表现形式,对数据进行表述。对于 YANG 模型来说,每个都有唯一标识命名空间 URI,用于区分。
简单来说,通过 YANG,对下发配置进行约束,如下的公式很好地描述了 YANG:
data(下发的数据)+ YANG = 下发给设备的配置

上图很好地表示了 YANG 起到的作用,YANG 本身并不是数据,而更像是一种配置模板,起到约束数据的作用。
那么 YANG Model 一般是由谁定义的呢?
YANG Model 的定义,主要有两个角色:
- 标准化的 YANG Model,由 IETF、OpenConfig 等机构进行规划定义。这类的 YANG 主要是考虑到多尝试的兼容性问题,而推出的统一的 YANG Module。所有厂商都需要支持。
- 各个厂商实现自定义私有的 YANG。这类 YANG Model 主要是为了厂商实现某些私有或特有功能。例如 Cisco 中有许多私有的协议,如 EIGRP、BGP 的某些功能只有思科设备上有。
YANG 的结构
YANG Module 以层次化树形结构被组织起来,每个模块可以引入外部其他的模块,包含其子模块的数据。
简单来说,就是可以将模块作为参数,引入其他的模块进行使用。
YANG 定义了很多的内置类型,并提供了自定义类型的机制,类似于 C 中的 typedef
。
在 YANG 中定义了四种类型,用于将数据模型化:
Leaf Nodes:
一个节点用于表示数字或字符串等简单的数据。但只能表示一个值,不能拥有子节点。
YANG 表示:
go
leaf host-name {
type string;
description "Hostname for this system";
}
XML 表示:
xml
<host-name>my.example.com</host-name>
JSON 表示:
json
{
"host-name": "my.example.com"
}
Leaf-List Nodes:
表示由 leaf node 构成的列表。
YANG 表示:
go
leaf-list domain-search {
type string;
description "List of domain names to search";
}
XML 表示:
xml
<domain-search>high.example.com</domain-search>
<domain-search>low.example.com</domain-search>
<domain-search>everywhere.example.com</domain-search>
JSON 表示:
json
[
{"domain-search": "high.example.com"},
{"domain-search": "low.example.com"},
{"domain-search": "everywhere.example.com"}
]
Container Nodes:
类似于编程语言中的 MAP 形式,将多个 node 组装到一起。一个 container node 可以包含多个任意类型的 node 节点,如 leafs、lists、leaf-lists,及本身 container 的类型。
YANG 表示:
fsharp
container system {
container login {
leaf message {
type string;
description
"Message given at start of login session";
}
}
}
XML 表示:
xml
<system>
<login>
<message>Good morning</message>
</login>
</system>
JSON 表示:
json
{"system":{"login": {"message": "Good morning"}}}
List Nodes:
由一个或多个 key leaf 和多个任意类型的子节点组成,类型包括 leafs、lists、containers 等。
其中 key leaf 用于表示当前 list 的唯一性。
YANG 表示:
typescript
list user {
key "name";
leaf name {
type string;
}
leaf full-name {
type string;
}
leaf class {
type string;
}
}
这里的 name 作为唯一的标识符。
XML 表示:
xml
<user>
<name>glocks</name>
<full-name>Goldie Locks</full-name>
<class>intruder</class>
</user>
<user>
<name>snowey</name>
<full-name>Snow White</full-name>
<class>free-loader</class>
</user>
<user>
<name>rzell</name>
<full-name>Rapun Zell</full-name>
<class>tower</class>
</user>
List Nodes 和 Leaf-List Nodes 的区别在于,Leaf-List Nodes 仅能包含类型是 Leaf Nodes 的节点,而 List Nodes 可以包含任意类型。
YANG 的其他特性
对于 YANG 来说,本身支持很多特性:
- 配置状态数据,对于定义那些不能配置的配置信息。
- 内置大量的基础类型,如 binary、bits、boolean 等。
- 派生类型,自定义去定义如 binary 等类型。
- 可重用组,引用通过 grouping 陈述定义的组,用于解耦和封装。
- 支持 choices,类似于枚举。
- 使用
augment
对 model 进行约束。 - 提供 RPC 调用。
- 提供通知定义。
更多功能,可以参考 YANG - RFC 文档。
PYANG - 更好的浏览 YANG Model
在了解 YANG 语言提供的强大功能后,一般在项目中,会使用由 Python 开发的 Pyang
工具来浏览 YANG 模型。
简单提一下安装方法,目前 Pyang 支持 Python2 和 Python3。
可以通过 docker 打包 Python 镜像后,作为运行环境:
perl
[root@localhost pyang-env]# ls
Dockerfile requirements.txt yang_modules
[root@localhost pyang-env]# cat Dockerfile
FROM python:3.8.5
ENV MY_PROXY_URL="http://xxx:80"
ENV HTTP_PROXY=$MY_PROXY_URL \
HTTPS_PROXY=$MY_PROXY_URL \
FTP_PROXY=$MY_PROXY_URL \
http_proxy=$MY_PROXY_URL \
https_proxy=$MY_PROXY_URL \
ftp_proxy=$MY_PROXY_URL
WORKDIR /src
COPY ./requirements.txt /
RUN pip install --no-cache-dir pyang
ENV MY_PROXY_URL=
ENV HTTP_PROXY=$MY_PROXY_URL \
HTTPS_PROXY=$MY_PROXY_URL \
FTP_PROXY=$MY_PROXY_URL \
http_proxy=$MY_PROXY_URL \
https_proxy=$MY_PROXY_URL \
ftp_proxy=$MY_PROXY_URL
使用 docker run -v /home/xx/pyang-env/yang_modules:/src -it --name pyang-env pyang-image /bin/bash
启动运行环境。
接着去 YANG 的 Github
中,下载由 IETF 或各个厂商开发后的 YANG Module。这里以 IOS-XE 版本为 633 的 YANG Module 为例。
可以看到有很多类似的 YANG 文件:

这时就可以通过 Pyang 工具,来浏览内容:
sql
root@a8af90280cf1:/src/633# pyang -f tree ietf-interfaces.yang
module: ietf-interfaces
+--rw interfaces
| +--rw interface* [name]
| +--rw name string
| +--rw description? string
| +--rw type identityref
| +--rw enabled? boolean
| +--rw link-up-down-trap-enable? enumeration {if-mib}?
+--ro interfaces-state
+--ro interface* [name]
+--ro name string
+--ro type identityref
+--ro admin-status enumeration {if-mib}?
+--ro oper-status enumeration
+--ro last-change? yang:date-and-time
+--ro if-index int32 {if-mib}?
+--ro phys-address? yang:phys-address
+--ro higher-layer-if* interface-state-ref
+--ro lower-layer-if* interface-state-ref
+--ro speed? yang:gauge64
+--ro statistics
+--ro discontinuity-time yang:date-and-time
+--ro in-octets? yang:counter64
+--ro in-unicast-pkts? yang:counter64
+--ro in-broadcast-pkts? yang:counter64
+--ro in-multicast-pkts? yang:counter64
+--ro in-discards? yang:counter32
+--ro in-errors? yang:counter32
+--ro in-unknown-protos? yang:counter32
+--ro out-octets? yang:counter64
+--ro out-unicast-pkts? yang:counter64
+--ro out-broadcast-pkts? yang:counter64
+--ro out-multicast-pkts? yang:counter64
+--ro out-discards? yang:counter32
+--ro out-errors? yang:counter32
还可以转换成 js 浏览:
mipsasm
pyang -f jstree ietf-interfaces.yang >> ietf-interfaces.html

更多命令可以查看帮助文档。
这时,对于网络工程师来说,可以将其从学习各厂商不同的配置命令转化到学习 Yang Module 中,更加聚焦功能,而不用再花费时间去学习相同的功能不同的命令。
YANG-Suite 介绍
YANG-Explorer 是一个用于浏览 YANG Model 的 WEB 服务,并提供生成 NETCONF RPC payload 等实用的功能。但由于其使用 Flash 编写,而在 2020 年 12 月后,Flash 已经被禁用,导致该工具无法使用。有兴趣的同学,可以安装老版本带 flash 的浏览器测试学习。
安装可以采用 docker:
bash
docker pull robertcsapo/yang-explorer
docker run -it --rm -p 8088:8088 robertcsapo/yang-explorer
最新 CISCO 开源了一个产品为 YANG-Suite,基于 YANG-Explorer 拓展了许多功能,并可以使用 docker-compose 启动,兼容性更好,预计未来会主流接受。
例如下面使用其生成 NETCONF RPC Payload:

### YANG 与 NETCONF
YANG 在早期是专为 NETCONF 而开发的一种语言,后来才被普及到各个协议中。关于 NETCONF 的介绍,可以参考相关资料。
下面主要涉及具体的操作,使用的设备是 ASR9000(IOS-XR 6.3.3)版本。
由于 NETCONF 本身采用 C/S 架构,需要在设备端打开:
```undefined
netconf agent ssh
```
在客户端方面,可以使用 `ssh` 进行测试:
NETCONF 会首先使用 Hello 建立链接,报告所拥有的能力。
````xml
[root@localhost ~]# ssh cisco@ip -p 830 -s netconf
Password: