// //
//

Loading

数据模型与网络自动化

传统人工 CLI 配置网络的模式,已经不在适用当代的网络,面临着兼容性,容错率低,效率低下等等问题,详细的内容可阅读这篇传统CLI面临的挑战

在这样的大背景下,各种网管协议应运而生。但这时就产生一个问题,以怎样的格式和内容去传递配置?

YANG 就是为了解决该问题而出现的,在解释 YANG 前,我们先来回忆下,传统 CLI 是如何下发配置的?

常常是由网络工程师通过 console/Telnet/SSH 等方式登录上设备,然后直接对设备进行配置,这时自然不用考虑怎样传参的问题,只要懂得设备的命令,直接上去敲就可以。

而 CLI 这样的配置,是一种无结构化的数据。

!
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 目的就是为了使用自动化,可编程化的方案代替人工,从而满足当下网络的各种业务场景。

此时配置结构化的数据就成了必然。

于是各个厂商开始对配置进行结构化的约定,在 NETOCNF 中,配置使用 XML 表示,进行参数的下发。

比如对接口的 MTU 进行更改:

 <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 主要是为了厂商实现某些私有或特有功能 YANG. 比如 Cisco 中有许多私有的协议,如 EIGRP,BGP 的某些功能只有思科设备上有。

YANG 的结构

YANG Module 以层次化树形结构被组织起来,每个模块可以引入外部其他的模块,包含其子模块的数据。

简单来说,就是可以将模块作为参数,引入其他的模块进行使用。

YANG 定义了很多的内置类型,并提供了自定义类型的机制,类似于 C 中的 typedef.

在 YANG 中定义了四种类型,用于将数据模型化:

Leaf Nodes:

一个节点用于表示数字或字符串等简单的数据。但只能表示一个值,不能拥有子节点。

YANG 表示:

 leaf host-name {
           type string;
           description "Hostname for this system";
       }

xml 表示:

 <host-name>my.example.com</host-name>

json 表示:

{
    "host-name": "my.example.com"
}

Leaf-List Nodes:

表示由 leaf node 构成的列表。

YANG 表示:

 leaf-list domain-search {
         type string;
         description "List of domain names to search";
     }

xml 表示:

<domain-search>high.example.com</domain-search>
<domain-search>low.example.com</domain-search>
<domain-search>everywhere.example.com</domain-search>

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 表示:

 container system {
         container login {
             leaf message {
                 type string;
                 description
                     "Message given at start of login session";
             }
         }
     }

xml 表示:

 <system>
       <login>
         <message>Good morning</message>
       </login>
     </system>

json 表示:

{"system":{"login": {"message": "Good morning"}}}

List Nodes

由一个或多个 key leaf 和多个任意类型的子节点组成,类型包括,leafs,
lists, containers 等。

其中 key leaf 用于表示当前 list 的唯一性。

YANG 表示:

 list user {
         key "name";
         leaf name {
             type string;
         }
         leaf full-name {
             type string;
         }
         leaf class {
             type string;
         }
     }

这里的 name 作为唯一的标识符。

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 镜像后,作为运行环境:

[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 工具,来浏览内容:

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 浏览:

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:

YANG

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

Screenshot showing the selected YangModel, various parameters such as the selected value, mode, datastore, and RPC window with the RPC textbox displaying the RPC

YANG 与 NETCONF

YANG 在早期是专为 NETCONF 而开发的一种语言,后来才被普及到各个语言中,关于 NETCONF 的介绍,可以参考这篇。

下面主要涉及具体的操作,使用的设备是 ASR9000(IOS-XR 6.3.3)版本。

由于 NETCONF 本身采用 C/S 架构,需要在设备端打开:

netconf agent ssh

在客户端方面,可以使用 ssh 进行测试:

NETCONF 会首先使用 Hello 建立链接,报告所拥有的能力。

[root@localhost ~]# ssh cisco@ip -p 830 -s netconf

Password:
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <capabilities>
  <capability>urn:ietf:params:netconf:base:1.1</capability>
  <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
  <capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
  <capability>urn:ietf:params:netconf:capability:validate:1.1</capability>
  <capability>urn:ietf:params:netconf:capability:confirmed-commit:1.1</capability>
  <capability>urn:ietf:params:netconf:capability:notification:1.0</capability>
  <capability>urn:ietf:params:netconf:capability:interleave:1.0</capability>
  <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04&amp;deviations=cisco-xr-ietf-netconf-monitoring-deviations</capability>
  <capability>http://cisco.com/ns/yang/cisco-xr-ietf-netconf-monitoring-deviations?module=cisco-xr-ietf-netconf-monitoring-deviations&amp;revision=2016-02-16</capability>
  <capability>http://cisco.com/ns/yang/Cisco-IOS-XR-Ethernet-SPAN-cfg?module=Cisco-IOS-XR-Ethernet-SPAN-cfg&amp;revision=2015-11-09</capability>
  <capability>http://cisco.com/ns/yang/Cisco-IOS-XR-Ethernet-SPAN-datatypes?module=Cisco-IOS-XR-Ethernet-SPAN-datatypes&amp;revision=2015-11-09</capability>
  <capability>http://cisco.com/ns/yang/Cisco-IOS-X

每个 capability 都可包含四部分内容:

  • Model URI
  • Module Name ,Revision Date
  • Protocol Features
  • Deviations - 修改自那个 Module
 <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&amp;revision=2010-10-04&amp;deviations=cisco-xr-ietf-netconf-monitoring-deviations</capability>
 
 Model URI = urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring
 Module Name = module=ietf-netconf-monitoring
 Revision = 2010-10-04
 Protocol Features = NULL
 Deviations = cisco-xr-ietf-netconf-monitoring-deviations

使用 ncclient 操作 NETCONF 设备, 使用参见 ncclient-github

获取 running 配置:

from ncclient import manager

host = "10.1.1.22"
username = "cisco"
password = "cisco"
device_params = {"name": "iosxr"}

with manager.connect(host=host, port=830, username=user, hostkey_verify=False, password=password) as m:
    c = m.get_config(source='running').data_xml
    with open("%s.xml" % host, 'w') as f:
        f.write(c)

上面演示了 NETCONF 中 get-config 操作,其余配置或过滤的功能,可参考文档。

需要注意一点的是,在配置时,payload 的生成一般通过上面介绍的 YANG-Suite 工具。

YANG 与 RESTCONF

RESTCONF 和 NETCONF 很像,简单来说,就是将 HTTP 融入了 NETCONF 中,采用 REST 风格替代 SSH 和 RPC 的交互方式。

更详细的内容,可参看这一篇。RESTCONF,下面主要集中在具体操作。

先来看下 RESTCONF URL 的内容:

https://<ADDRESS>/<ROOT>/<DATASTORE>/[YANGMODULE:]CONTAINER/<LEAF>[?<OPTIONS>]
  • ADDRESS:表示 RESTCONF 代理的 IP
  • ROOT:表示 restconf 请求的入口点
  • DATASTORE:被查询的数据库
  • [YANGMODULE:]CONTAINER - 使用基础的模块名称
  • : 在 Container 内的独立 node
  • ?:返回结果的过滤参数

这里以 NSO - 思科的产品为例,直接操作设备也同理,比如 IOS-XE 的设备。

首先查询是否具有 RESTCONF 功能:

http://xx:8080/.well-known/host-meta

# Response 包含具有 RESTCONF 内容 
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
    <Link rel='restconf' href='/restconf'/>
</XRD>

# 里面的内容表示 ROOT 的内容,作为 RESTCONF 的入口点。

查看 NETCONF 支持的能力:

http://xx:8080/restconf/data/netconf-state/

查看 RESTCONF 支持的能力:

http://xx:8080/restconf/data/restconf-state/

NOTE:

需要在 Headers 中,指定发送和接受数据的格式:

Content-type:

  • application/yang-data+json
  • application/yang-data+xml

Accept:

  • application/yang-data+json
  • application/yang-data+xml

查询 NSO 纳管的设备 - GET Method:

http://10.124.207.154:8080/restconf/data/tailf-ncs:devices/device=ASR9K/name/

修改接口描述 - Patch Method:

http://10.124.207.154:8080/restconf/data/tailf-ncs:devices/device=ASR9K/config/tailf-ned-cisco-ios-xr:interface/TenGigE/

{
    "tailf-ned-cisco-ios-xr:TenGigE": 
        {
            "id": "0/0/1/0",
            "description": "restconf-test"
        }
}

总结

YANG 的本质是一种对数据进行结构化描述的语言,本身不是数据,而是起到约束数据的作用。

至于为什么需要 YANG,原因在于传统 CLI 的方式,不在适合当代网络的要求。而且结构化,统一的数据更容易被机器所处理。

现在 YANG 被广泛使用,特别是可编程化的特点,像让自动化,动态编排服务,甚至网络自我调节与优化都成为了可能。

下图中很好的描述了 YANG 所发挥的作用,在设备上通过 YANG 的定义,提供如 RESTCONF,NETCONF 的接口,让其通过 HTTP 或 RPC 管理设备。

在控制器中,根据定义的 YANG Module 来开发各种客户端,去调用设备。

Cisco Connect Toronto 2018 model-driven programmability for cisco i…

参考

RFC6020 - YANG

RFC6020 - YANG1.1

YANG-Study

YANG Models

yang-explorer

RESTCONF-URL

posted @ 2021-03-04 16:24  来份锅包肉  阅读(1534)  评论(0编辑  收藏  举报