背景

随着互联网的发展,网络日趋复杂且规模庞大。网络的稳定性/可预测的故障恢复时间如何保障?大量的新设备和服务如何安全快速地融入老的系统?不同的厂商接口如何统一管理?这些问题需要大量的优秀工程师去处理,但另一个事实是,相当一部分的网络故障是由人为操作不当引起的。通过自动化网络管理去减轻工程师的运维负担是大势所趋。在 2002 年 IAB(Internet Architecture Board )就网络管理所面临的问题作了讨论(RFC3535),确定了四个解决问题的关键方向,支持事物/可回滚/实现成本低/配置可存储和恢复。随即 NETCONF 工作小组成立,基于这几个方向制定了 NETCONF 标准(RFC6241). NETCONF 协议包含四层,数据层/操作层/调用层/传输层, 但是缺少一种定义数据模型的方式,2008 年 NETMOD 工作组成立,2009 年 NETMOD 发布了 YANG(RFC7950), 一种为 NETCONF 定义数据模型的标准语言。

NECONF

术语

urn:ietf:params:netconf:capability:{name}:1.x

工作机制

NETCONF 是 C/S 架构的模式,Client 和 Server 通过 RPC 以 xml 形式交换数据。Client 端作为网络管理服务的一部分,可以是脚本,也可以是应用等。Server 端一般是网络设备。

NETCONF 架构

四个层次

NETCONF 包含了四个层次,数据层/操作层/RPC/传输层, 对于普通用户,只需关注数据层和操作层即可。

NETCONF 的四个层次

Content

设备模型数据,YANG 数据建模语言正是用来描述这些模型数据的。

Operations

操作层定义了一系列用于网络设备管理的操作。

NETCONF operations 列表

RPC

定义了一种独立于协议之上( transport-protocol-independent)的数据组织和传输方式。

Transport Protocol

定义了数据的传输方式, NETCONF 并没有指定协议实现者在 C/S 之间使用什么传输协议,只是规定了一些  传输协议必须满足的要求,比如面向连接/支持 kee-alive 等,具体的参见RFC6241.

实际环境中的使用

我们使用 juniper 的 vsrx 来做 NETCONF 的使用示例。

vsrx 安装
  1. 下载vsrx
  2. 使用 vmware 等虚拟化软件安装并启动 vsrx
  3. 配置 vsrx 3.1 通过缺省用户名和密码登录(root/空) 3.2 进入操作模式
cli

3.3 进入配置模式

configure

3.4 设置密码

set system root-authentication plain-text-password

3.5 设置远程登录管理用户

set system login user remote class super-user authentication plain-text-password

3.6 设置网络

set interfaces fxp0 unit 0 family inet address 172.16.240.189/24

3.7 设置 netconf ssh port

set system services netconf ssh port 830

3.8 提交配置

commit check commit
NETCONF clients

client 列表

创建一个 session

连接完成后,server 端会返回自己的 capabilities

package main import ( "fmt" "golang.org/x/crypto/ssh" "log" "github.com/Juniper/go-netconf/netconf" ) func main() { sshConfig := &ssh.ClientConfig{ User: "root", Auth: []ssh.AuthMethod{ssh.Password("r00ttest")}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } s, err := netconf.DialSSH("172.16.240.189", sshConfig) if err != nil { log.Fatal(err) } defer s.Close() fmt.Println(s.ServerCapabilities) fmt.Println(s.SessionID) }
获取 running 配置

你会看到 running 的所有配置

package main import ( "fmt" "golang.org/x/crypto/ssh" "log" "github.com/Juniper/go-netconf/netconf" ) func main() { sshConfig := &ssh.ClientConfig{ User: "root", Auth: []ssh.AuthMethod{ssh.Password("r00ttest")}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } s, err := netconf.DialSSH("172.16.240.189", sshConfig) if err != nil { log.Fatal(err) } defer s.Close() fmt.Println(s.ServerCapabilities) fmt.Println(s.SessionID) // Sends raw XML reply, err := s.Exec(netconf.RawMethod("<get-config><source><running/></source></get-config>")) if err != nil { panic(err) } fmt.Printf("Reply: %+v", reply) }
修改配置并提交

包括错误回滚

package main import ( "fmt" "golang.org/x/crypto/ssh" "log" "github.com/Juniper/go-netconf/netconf" ) func doRpc(s *netconf.Session, xml string) { reply, err := s.Exec(netconf.RawMethod(xml)) if err != nil { panic(err) } fmt.Printf("Reply: %+v", reply) } func main() { sshConfig := &ssh.ClientConfig{ User: "root", Auth: []ssh.AuthMethod{ssh.Password("r00ttest")}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } s, err := netconf.DialSSH("172.16.240.189", sshConfig) if err != nil { log.Fatal(err) } defer s.Close() fmt.Println(s.ServerCapabilities) fmt.Println(s.SessionID) //xml := "<rpc>" xml := "" xml += "<edit-config>" xml += " <target><candidate/></target>" xml += " <error-option>stop-on-error</error-option>" xml += " <config>" xml += " <configuration>" xml += " <interface>" xml += " <name>fxp0</name>" xml += " <unit>" xml += " <name>0</name>" xml += " <family>" xml += " <inet>" xml += " <address>172.16.240.189/24</address>" xml += " </inet>" xml += " </family>" xml += " </unit>" xml += " </interface>" xml += " </configuration>" xml += " </config>" xml += "</edit-config>" //xml += "</rpc> // Sends raw XML doRpc(s, xml) xml = "<rpc><commit></commit></rpc>" doRpc(s, xml) }

Distributied transactions

当有多个设备需要修改配置时,为了保证操作的原子性,我们可以先锁定所有设备的配置,修改完成后,利用 confirmed-commit 特性,check 完之后再确认提交。

distributed transactions

YANG

YANG 是为 NETCONF 而生的数据建模语言, 应用在 NETCONF 的 content 层和 operation 层。YANG 用层级的方式描述 NETCONF 的配置和状态数据,RPC 及通知,覆盖了 NETCONF C/S 的整个生命周期。YANG 模型可以转换成 JSON 和 XML。

statements

YANG 定义了一系列的模型描述关键字。

statements

types

YANG 定义了一系列的基础类型,同时可以用 typedef 描述自定义的类型, 一些通用的扩充类型可以参见RFC6021

基础类型

使用 YANG 来描述一个 DHCP 配置

DHCP 配置
# Sample configuration file for ISC dhcpd default-lease-time 600; max-lease-time 7200; subnet 10.254.239.0 netmask 255.255.255.224 { range dynamic-bootp 10.254.239.10 10.254.239.20; option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; max-lease-time 1200; } shared-network 224-29 { subnet 10.17.224.0 netmask 255.255.255.0 { range 10.17.224.10 10.17.224.250; option routers rtr-224.example.org; } subnet 10.0.29.0 netmask 255.255.255.0 { range 10.0.29.10 10.0.29.230; option routers rtr-29.example.org; } }
YANG 模型
module dhcp { // dhcp module namespace "songtianyi:yang:dhcp"; prefix dhcp; import ietf-yang-types { // 导入自定义类型 prefix yang; } import ietf-inet-types { prefix inet; } organization "TIANYUAN CLOUD TECH"; description "Partial data model for DHCP, based on the config of the ISC DHCP reference implementation."; container dhcp { // 根结点 description "configuration and operational parameters for a DHCP server."; leaf max-lease-time { // 描述最大租赁期 type uint32; units seconds; // 定义单位 default 7200; // 最大租赁期默认值 } leaf default-lease-time { type uint32; units seconds; must 'current() <= ../max-lease-time' { // 约束, default-lease-time 必须小于等于 max-lease-time error-message "The default-lease-time must less or equal max-lease-time"; } default 600; // 如果默认值大于 max-lease-time 也会报错 } uses subnet-list; // 引用 grouping 描述 container shared-networks { list shared-network { key name; leaf name { type string; } uses subnet-list; } } } grouping subnet-list { description "A reusable list of subnets"; list subnet { key net; leaf net { type inet:ip-prefix; } container range { presence "enables dynamic address assignment"; // presence 表明,range 作为子节点存在,即使 range 没有定义子节点 leaf dynamic-bootp { type empty; description "Allows BOOTP clients to get addresses in this range"; } leaf low { type inet:ip-address; mandatory true; } leaf high { type inet:ip-address; mandatory true; } } container dhcp-options { description "Options in the DHCP protocol"; leaf-list router { type inet:ip-address; ordered-by user; } leaf domain-name { type inet:domain-name; } leaf max-lease-time { type uint32; units seconds; default 1200; } } } } }

YANG tools

NETCONF&YANG

前边分别介绍了 NETCONF 和 YANG, 那么它们是如何结合起来的呢?

<dhcp xmlns="http://yang-central.org/ns/example/dhcp" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> <default-lease-time nc:operation="merge">10800</default-lease-time> </dhcp>

在 netconf client 发送 xml 给 netconf server 的时候将 YANG 模型加入 xml 即可,server 会根据模型来检验 xml 里的配置数据,因此 default-lease-time 的 10800 配置会返回 rpc-error。需要注意的是,这些特性依赖于 netconf server 的具体实现,因此需要通过 server 端返回的 capbilities 来检查是否支持该特性。

NSO

在网络设备管理方面起步早且做的好的,应当是 tail -F systems, 该公司的 NSO(Network Service Orchestrator)产品已被 cisco 收购。

NSO 架构

NSO Logical Architecture

Web User Interface

参见视频