龙空技术网

NETCONF、YANG、ncclient理论和实战(上)

弈心 402

前言:

此刻你们对“netconf基于什么协议”大约比较关怀,小伙伴们都需要剖析一些“netconf基于什么协议”的相关知识。那么小编在网络上汇集了一些关于“netconf基于什么协议””的相关知识,希望同学们能喜欢,同学们快快来学习一下吧!

最近让我写一篇NETCONF在网络运维中实际应用的读者越来越多,趁着最近回沙特后能把KAUST堆满仓库的3850, 9200, 9300等IOS-XE真机设备拿出来做实验,趁这个机会我就写写NETCONF,YANG和ncclient,分为上、下两篇,上篇讲NETCONF和YANG,下篇讲ncclient,包含理论和实战。以后有时间也会讲讲REST和RESTCONF。

NETCONF的前世今生

2002年6月,互联网架构委员会(Internet Architeture Board,简称IAB)举办了一个主题为Network Management的workshop,邀请了一大帮研发界业内名气响当当的巨佬(大多来自IETF)共同商议讨论彼时普遍使用的网络管理协议,找出它们各自的优势和缺点,并列出一个优秀的网络管理协议必须具备的特征,准备为开发下一代网络管理协议(NextGen Network Management Protocol)做准备。2003年5月,IETF发布了RFC 3535(Overview of the 2002 IAB Network Management Workshop),正式提出了下一代网络管理协议应该具备的七大特征:

在这个背景下,IETF于2006年12月率先发布了RFC 4741, 也就是NETCONF这个基于XML,用来替代CLI、SNMP的网络配置和管理协议。在随后几年加加改改进行一番修订后,IETF又于2011年6月以RFC 6241作为终稿将其再次发布。

虽然NETCONF年龄不算小,但是倒退10年前你要是问一个网络工程师什么是NETCONF(更别提YANG了),大概率你会看到对方一脸懵逼的把你看着,因为当时主流的思科IOS设备根本就不支持NETCONF,当时的思科对NETCONF并不感冒,而是自己闭门造车分别在2007年和2012年搞出了WSMA(Web Service Management Agent)和onePK这两个API。那些年跟随思科的步伐一路从CCNA,CCNP,CCIE摸爬滚打起来的网工压根就没听说过还有这么一个书上不会教,考试不会考,工作中也基本用不到的非常小众的技术。十年河东十年河西,这些年随着SDN和网络运维自动化技术的强势崛起,NETCONF终于在诞生10多年后在传统计算机网络这个行业里有了一定的曝光率,跟着RESTCONF和gRPC这俩哥们一起站在时代的风口上飞了起来。

NETCONF理论部分

关于NETCONF的理论部分网上有很多资料,最权威的肯定还是RFC 6241,这里做一下总结:

1. NETCONF的协议框架分为四层:由低到高分别为安全传输(Secure Transport),消息(Messages),操作(Operations)和内容(Content):

安全传输层最常见、最常用的是SSH,这也是NETCONF和同为最近几年炒的火热的REST(基于WEB)最大的区别消息层基于Remote Procedure Call(远程调用)这个协议,其作用是提供一个简易的不依赖于传输层,生成RPC和通知消息框架的通信协议。在后面的NETCONF实验中你会多次看到<rpc><rpc-reply>这两个东西。操作层定义了一组用来配置、复制、删除设备命令以及获取设备信息的基本操作,基本操作包括get, get-config, edit-config, copy-config, delete-config, lock, unlock, close-session, kill-session,这些基本操作都是在XML语言下被调用,比如<get><edit-config>等等,后面实验部分会讲到。内容层由管理数据内容的数据模型定义,该数据模型也就是我们后面会讲到的YANG。

2. NETCONF的编码格式基于XML,基于XML来做网络管理主要是看中了XML强大的数据表示能力(对初学者来说XML其实并不怎么友好,不如JSON, YAML那么易读和容易上手,这是我个人的观点)。

3. NETCONF网络架构由客户端和服务器组成,客户端就是我们的主机,服务器就是被操控的交换机或者路由器,NETCONF默认使用端口830,可以更改。

4. NETCONF协议中还有一个重要的概念叫做数据集(Datastores),数据集的作用是用来存储一份配置数据的备份,确保设备能从开机时的初始状态进入到它能正常运行时的工作状态(说白了就是改了配置后需要write memroy,不然重启设备后配置会丢失)。数据集分为Running(类似于思科的running config), Start-up(类似于思科的startup config)和Candidate(思科IOS-XR会用到)三种,其中只有Running这个datastore是强制使用的。

讲完NETCONF的理论部分,下面再来看看YANG。

什么是数据模型?

在讲YANG之前,我们首先需要知道什么是数据模型。

数据模型的作用是用来描述一组具有统一标准的数据,并用明确的参数和模型来将数据的呈现标准化、规范化。举个例子,不同厂商之间对一些行业术语的规范及具体参数存在较大差异,比如用来区分路由协议优先级,在思科这边被称作管理距离(Administrative Distance)的东西到了Juniper那边被改叫做Route Preference,并且它们分配给各个路由协议的AD和RP值也不一样,比如RIP在思科的AD为120,在Juniper的RP为100, 又比如OSPF在思科的AD为110,而在Juniper这边OSPF还被分为OSPF Interal(RP值为10),OSPF External(RP值为150)。虽然不同厂商之间对某些技术标准存在这样那样的差异,但是对于绝大部分技术它们还是遵守统一标准的,比如VLAN。

用来描述VLAN的数据无外乎如下几点:

1. VLAN ID (1-4096的整数,rw类型)

2. VLAN Name (用字符串代表的VLAN名称,rw类型)

3. VLAN State (用枚举表示的down/up或shutdown/no shutdown表示的VLAN状态,ro类型)

可以看到类似于这种明确定义了数据内容及其数据类型和范围,以及rw、ro类型的一套模型,就被叫做数据模型。

YANG

YANG是一种“以网络为中心的数据模型语言”(Network-centric data modeling language),由IETF于2010年10月(也就是NETCONF终稿发布之前的一年)在RFC 6020中被提出,其诞生之初的目的很明确, 是专门为NETCONF量身打造的建模语言,不过现在也被REST和其他协议所采用。

YANG模型(Model)

YANG的模型分为标准(Open或者Standard)和私有(Native)两种类型,其中标准类型中比较著名的有IETF, IEEE, OpenConfig等国际知名组织制定的模型(IETF制定的YANG模型最常见)。除标准YANG模型之外,各家厂商又根据自家产品的不同设计了私有的YANG模型,比如思科、Juniper、华为、Fujitsu、诺基亚等都有自家的YANG模型。

其中思科的YANG模型又分为Cisco Common和Cisco Platform Specific,其中前者为思科所有OS(IOS-XE, IOS-XR, NX-OS)通用的YANG模型,后者为一些OS上独占的YANG模型。

YANG模块(Module)

模块(Module)是YANG定义的基本单位,一个模块可以用来定义一个单一的数据类型,也可以增加一个现有的数据模型和其他节点:

下面是一个叫做ietf-interfaces,由IETF制定,用来描述设备端口参数的YANG模块:

在Github下载YANG模块

在Github()上存放着大部分标准(standard)和私有(vendor)的YANG模型,截止2020年9月,标准模型中包含IETF,IEEE,ETSI等国际知名组织和协会制定的YANG模块,私有模型中包含思科,Juniper,华为,诺基亚,富士通在内的厂商自己制定的YANG模块。

我们可以通过git clone来下载上述所有标准和私有的YANG模型及其对应的模块:

git clone 

下载完毕后,当前目录下多出来了一个名叫yang的子目录,其中yang/standard/ietf/RFC下包含了全部由IETF制定的YANG模块,其中也包含我们上面举例的ietf-interfaces模块(不在截图里)。

用cat ietf-interfaces.yang查看该模块的内容:

你也许会问,怎么和上面我们举例的ietf-interfaces模块内容不一样?这是因为上面的例子中我们是以树形格式(Tree View Format)展开ietf-interfaces模块,而这里用cat查看的是该模块的源代码。我们可以用pyang这个Python模块来以树形格式的形式查看一个YANG模块的具体结构。

Pyang

Pyang是Python专为YANG开发的一个开源模块,主要有三个功能:1. 用来验证YANG模块代码的准确性,2. 将YANG模块转换成其他格式(比如我们前面讲到的树形格式), 3. 从YANG模块中生成代码。这里我们主要讲下如何使用Pyang来将刚才的ietf-interfaces.yang这个模块转化为树形格式。

首先通过pip下载安装pyang:

然后回到yang/standard/ietf/RFC下,使用命令pyang -f tree ietf-interfaces.yang即能将ietf-interfaces这个YANG模块转换成树形模式查看。

实验环节

讲完理论后来做实验。实验环境很简单,就是一台CENTOS 7主机和一台思科3850的交换机直连。

实验拓扑

主机操作系统:CentOS 7

交换机型号:WS-C3850-48P-S

交换机OS版本:IOS-XE 16.09.05 (Fuji)

主机IP: 172.16.224.27

交换机IP: 172.16.224.28

实验设计的端口为交换机的GigabitEthernet1/0/33,其初始配置如下:

开始实验前先提几点使用NETCONF的重点:IOS-XE版本必须为16.3以上。Netconf默认使用TCP端口830, 可以更改。Netconf的传输协议基于SSH,在交换机上必须开启SSH, 并且用户特权级别必须为15。如果交换机配置了AAA+TACACS(比如说思科的ISE),必须保证配置了“aaa authorization exec default local”,然后使用交换机本地创建的用户名(非ISE上的用户名),否则在主机端会出现“Permission denied, please try again.”,在交换机端会出现“%DMI-5-AUTHENTICATION_FAILED:”的错误:

实验步骤:首先在交换机上开启NETCONF,方法很简单,在全局模式下输入netconf-yang和netconfg ssh(可选,前面理论部分已经讲了,NETCONF默认使用的是SSH作为安全传输层协议,所以netconf ssh这条命令默认就是开启的,不需要特意配置)即可。其余的交换机初始配置,比如开启SSH和创建特权级别为15的用户请读者自行完成,这里就不讲了。

SW(config)#netconf-yang SW(config)#netconf ssh (默认是开启的)

2. 回到主机,通过SSH访问交换机的830端口:

3. 连接成功后,交换机会回复一个hello包,以及一长串capabilities,也就是该交换机支持的yang model:既有思科的,也有IETF的,由于回显内容过多,下图只截取部分以作演示:

4. 随后我们复制粘贴下列XML代码向交换机回复一个hello包(交换机不会做出任何回应),之后主机和交换机之间的netconf session即建立成功。

<?xml version="1.0" encoding="UTF-8"?><hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">    <capabilities>        <capability>urn:ietf:params:netconf:base:1.0</capability>    </capabilities></hello>]]>]]>

这里简单讲下XML语言的格式和内容,XML指令以<?xml version="1.0" encoding="UTF-8"?>开头,其中:

<?:表示一条XML指令的开始。xml:表示此文件是XML文件。version:NETCONF协议版本号。encoding:字符集编码格式,当前仅支持UTF-8编码。?>:表示一条XML指令的结束。

<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">里:

hello表示主机(NETCONF客户端)向交换机(NETCONF服务器)回复的hello包。xmlns是XML Namespace(XML命名空间)的缩写,在XML里面,元素名称(你可以把它理解为Python中的变量名)是由开发者自己定义的,当将两个不同的文档合并成一个文档,如果两个文档里面使用相同的元素名时,就会发生命名冲突。比如说你和我分别开发了一个XML文档,我用name作为元素名称来描述一个人名,而你也用name作为元素名称来描述一个地名,虽然我俩描述的东西不一样,但是你我定义的元素名称(name)是一样的,当我俩的文档被合并成一个文档时,就会造成冲突,而XML命名空间的作用就是避免XML内元素的冲突。urn:ietf:params:xml:ns:netconf:base:1.0, 在RFC 4741中规定了所有涉及NETCONF协议的元素必须以urn:ietf:params:xml:ns:netconf:base:1.0作为XML命名空间。<capabilities>代表能力集,<capability>代表具体的能力,是NETCONF客户端和服务器互相向对方说明自己具备什么能力的作用,这里的<capability>urn:ietf:params:netconf:base:1.0</capability>表示客户端告诉服务器:我具备使用IETF制定的NETCONF协议的能力。和Python不一样,XML并没有严格要求缩进,但是为了美观和可读性,一般我们用两个空格或者四个空格做缩进。注意代码最尾部的]]>]]>,它是NETCONF客户端和NETCONF服务器用来表示消息请求或回复终止的部分(用来告知对方“我话说完了,轮到你了”),并不是XML语言本身的一部分,后面会说明为什么它很重要。

5. 发送下列XML代码向交换机查询Gi1/0/33端口的配置:

<?xml version="1.0" encoding="UTF-8"??><nc:rpc message-id="101" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">  <nc:get>    <nc:filter type="subtree">      <native xmlns=";>      <interface>        <GigabitEthernet>        <name>1/0/33</name>        <description></description>          <ip></ip>        </GigabitEthernet>       </interface>       </native>    </nc:filter>  </nc:get></nc:rpc>]]>]]>

随即交换机会回复一个rpc-reply包(下图红框中的部分),后面的内容即我们请求的Gi1/0/33端口的配置信息,包括该端口下的description和IP地址(为空)。

6. 如果你觉得交换机回复的rpc-reply不易读,可以将它复制粘贴到Code Beautify(),用Code Beautify下面XML Viewer提供的Tree View或者Beautify / Format让交换机的rpc-reply内容更易读。

注意复制RPC-REPLY内容时不要把末尾的]]>]]>给一并复制了(前面讲了它们不是XML语言的一部分),不然Code Beautify会报错:

7. 接下来我们用下面这段XML代码来查询交换机的running configuration。请自行尝试这里就不放截图了:

这里我故意没做缩进,就是为了告诉你XML没有严格要求代码缩进。

<?xml version="1.0"?><rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="102"><get-config><source><running/></source></get-config></rpc>]]>]]>

8. 用下面这段XML代码来为端口Gi1/0/33添加一个description,内容为test XML,表示该description是我们通过NETCONF配置的:

<?xml version="1.0"? encoding="UTF-8"??><rpc message-id="102" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">    <edit-config>        <target>            <startup/>        </target>        <config>            <native xmlns=";>                <interface>                    <GigabitEthernet>                        <name>1/0/33</name>                        <description>test XML</description>                    </GigabitEthernet>                </interface>            </native>        </config>    </edit-config></rpc>]]>]]>

这里我们使用到了<edit-config>这个前文NETCONF理论部分讲到的基本操作,通常<edit-config>下面会接一个<target>,表示需要修改配置的目标,<startup/>表示数据集,这里我们要更改的是startup这个数据集(也可以使用running/),后面的<native xmlns=";>表示这里我们使用了前面讲到了的思科私有(Native)YANG模型。

回到交换机上验证Gi1/0/33的配置:

9. 最后我们用下面这段XML代码给Gi1/0/33配置一个10.1.1.2 /24这个IP地址

<?xml version="1.0"? encoding="UTF-8"??><rpc message-id="103" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">    <edit-config>        <target>            <running/>        </target>        <config>            <native xmlns=";>            	<interface>            		<GigabitEthernet>            			<name>1/0/33</name>            			<ip>            				<address>            					<primary>            						<address>10.1.1.2</address>            						<mask>255.255.255.0</mask>            					</primary>            				</address>            			</ip>            		</GigabitEthernet>            	</interface>            </native>        </config>    </edit-config></rpc>]]>]]>

之后回到交换机上验证Gi1/0/33的配置:

关于NETCONF和YANG的理论和实战就讲到这里,可以看到NETCONF这种通过复制粘贴XML代码的操作方式对传统工程师来说很不适应,虽然不太好用,但NETCONF确实是SDN时代网工们必须掌握的技能之一。下篇我将继续讲解ncclient这个Python专为NETCONF客户端开发的第三方模块,看看NETCONF结合Python会不会省事一些。

标签: #netconf基于什么协议