OpenConfig初识(一)

引言

SDN技术的核心是转发与控制分离,由于Openflow在实际应用中有其局限性,逐渐地,Openflow已经不再是SDN技术的必备条件,网络可编程能力慢慢地成为衡量一套SDN架构的重要标准之一。

传统的网络设备进行可编程操作,一般是基于CLI与SNMP协议进行 。CLI通过命令行的方式实现人机交互,可以通过程序赋予网络一定的可编程能力,但它最大的问题是在不同厂商的设备之间,甚至同一设备不同版本之间存在较大差异,在当今云计算与SDN的浪潮之下,不适用于网络中的大规模自动化部署;SNMP虽然广泛应用于网络管理系统,但一般应用在网络监控领域,用来做信息采集,提供告警和可视化报表等,配置能力的缺失与复杂导致人们对其在网络配置方面使用甚少。

NETCONF协议

面向下一代网络,为了更好地实现网络可编程能力,提高自动化的水平,2006年IETF提出了NETCONF( Network Configuration Protocal)协议,是安装、编辑和删除网络设备配置的标准协议,该协议采用分层结构:安全传输层,消息层(RPC层),传输层和内容层。在 Netconf 的架构中,网络设备充当 Netconf Server 的角色,运维人员的角色则是 Netconf Client。

Netconf Server(网络设备)上面部署了 Netconf 应用,Netconf Client 需要调用 Server 上的应用所提供的函数/方法,但由于 Client 和 Server 不在同一个内存空间,无法直接调用,所以需要通过网络来表达调用的语义,并传达调用的数据,这个过程称为 RPC(远程过程调用)。

Netconf协议的内容层可以提供网络设备的配置数据和状态数据,由此,网络运维人员只需要关注数据本身,而不需要去关注设备的相关命令。基础网络设备在NETCONF协议的内容层所采用的数据格式通常是 XML,但也有厂商的数据格式采用了 JSON。虽然网络运维人员不再需要关注设备的相关命令了,但仍然无法直接使用 Netconf 配置设备,因为不同厂商的设备配置结构不同,无法直接使用 XML 或者 JSON 修改他们的设备配置。

YANG Model

为了解决配置结构的问题,需要将 XML 和 JSON 数据格式抽象成一个统一的标准的模型,这就是 YANG( Yet Another Next Generation)。YANG 是表达 Netconf 所操作的配置数据和状态数据的模板,它描述什么才是符合设备期望的数据。有了 YANG Model,配置结构就交给它去处理。

网络运维人员只需拿到设备厂商的YANG Model,通过阅读对应的YANG Model,将相关的配置或数据参数填入,即可以通过基于HTTP RESTful API的RESTConf或者基于SSH的Netconf或者基于HTTP2.0的gRPC对网络设备进行可编程操作,完成配置或数据读取任务。通过YANG和NETCONF,就实现了基于可编程技术的网络配置和管理,为自动化运维提供了基础。

NETCONF和YANG Model的出现,为网络自动化带来了极大的便利。配合自动化的程序,可以实现动态向网络设备下发配置,将数据面和控制面分离,组成软件定义的网络。网络设备对于NETCONF的支持,就是在设备注册YANG文件的数据模型路径,使设备能够根据YANG文件的数据模型路径获取数据或者写入配置。

但NETCONF仍不是理想的API,原因在于:1)各厂商设备支持NETCONF基本都使用私有YANG Model, 不同厂商设备不能识别其他厂商YANG文件;2)对于使用NETCONF运维平台的使用者,需要学习熟悉各厂商的NETCONF文档和YANG文件;3)虽然主流的 SDN Controller 的南向接口都支持 Netconf,但是在实际部署时,却无法用单一的 Controller 去控制多厂商的网络设备,通常都是各个厂商使用自己的 SDN Controller 控制自己的设备,然后再用 REST API 与用户的 SDN Controller 对接。

为了解决这些现实问题,Google 等网络设备的大用户一直在致力于推广一个能够替代 Netconf 的标准化接口: OpenConfig。

OpenConfig

OpenConfig试图创建一个与设备商无关的开放模型,用于网络配置和策略。OpenConfig 沿用了 Netconf 的协议框架,但是它不太关注底层的数据传输,而是更关注上层的数据表达和数据建模。

OpenConfig本身是基于标准化的NETCONF协议框架和建模语言YANG来开发,在YANG Model维度进行标准化,相当于YANG Model做了规范,需要各厂家设备全部能够识别OpenConfig YANG Model的YANG文件,这样,不同厂商的设备就可以通过统一模型的YANG文件来管理,不同的只是YANG文件中填入的参数。

目前,由于在网络管理、配置下发以及开放性等方面的优势,NETCONF基本已经成为实现数据中心运维自动化的主流协议。同时各大网络设备厂商也纷纷将NETCONF加入功能支持列表里。虽然由于私有YANG的问题导致在实际应用中还存在一些问题,但OpenConfig已经为解决这些问题提供了明确可行的思路。随着OpenConfig的逐步落地,数据中心自动化运维技术将迎来新一波浪潮。

OpenConfig GitHub

OpenConfig GitHub项目包含多个子项目,比如public, gnmi, ygot等等,刚接触到OpenConfig时,不如如何下手,事实上,子项目public中给出了很多例子,通过这些例子来初步认识OpenConfig,其中oc_by_example.md样例介绍了YANG Modeling, gRPC, Protocol Buffers, gNMI, Streaming Telemetry (Pub/Sub), TSDB可视化工具的概念和使用方法。

本节主要通过利用Docker容器介绍gRPC和Protocol Buffers,样例拓扑图如下图所示。

OpenConfig初识(一)_第1张图片

创建Docker容器

  1. 创建虚拟网络
# docker network create --subnet=172.20.0.0/24 ocnet
  1. 分别在两个终端中创建并开启Client和Server Docker容器
# docker run -it --net ocnet -h grpc_server --ip 172.20.0.2 openconfig/grpc_server:v1 /bin/bash
# docker run -it --net ocnet -h grpc_client --ip 172.20.0.3 openconfig/grpc_client:v1 /bin/bash

使用方法

  1. 写protocol buffer文件

protocol buffer是一种跨平台和跨语言的结构数据序列化工具,将结构化的数据(拥有多种属性)进行序列化,从而实现(内存与硬盘之间)数据存储和交换的功能。序列化就是按照 .proto 协议文件将数据结构或对象转换成二进制流的过程;反序列化是按照 .proto 协议文件将在序列化过程中所生成的二进制流转换成数据结构或对象的过程。

在传输数据量较大的需求场景下,Protocol Buffer比 XML、JSON 更小(3到10倍)、更快(20到100倍)、使用和维护更简单。

在grpc_client容器中,新建counters.proto文件,结构数据是通过ifconfig输出得到的数据包统计数,文件内容如下:

// counters.proto
syntax = "proto3";
package cclab;

service int_counter{
	rpc GetCounter(RxpacketRequest) returns (RxpacketReply) {};
}
// server端中有两个端口:lo和eth0,因此定义一个string类型的message,已决定获取哪个端口的ifconfig信息
message RxpacketRequest{
	string interface = 1;
}
// 为Rx packetd定义一个的message
message RxpacketReply{
	uint64 rxpackets = 1;
	string message = 2;
}
  1. 利用counters.proto编译源代码

此处,分别在容器的client端和server端,利用 protocol buffer编译器编译生成python类以供client端和server端的应用程序使用,在client容器端执行:

root@grpc_client:/home/user# python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. ./counters.proto

执行成功后,会生成counters_pb2.py和counters_pb2_grpc.py等新文件,可供client端和sever端的应用程序会用到的python函数和类。

  1. 写client端应用程序

首先,写一个脚本,导入产生的protobuf代码和其他一些强制性的库,如下counter_grpc_client.py所示:

'''counter_grpc_client.py'''
from __future__ import print_function
import grpc
import counters_pb2
import counters_pb2_grpc

def GetRxPackets(server_int):
	'''
	Args:
		int: (str) Server interfaces we're interested in.
	Returns:
		response: (str) The message which comes accross the gRPC.
	'''
	//创建一个连接server端的不安全gRPC通道,其中sever端地址为172.20.0.2,端口为50051
	channel = grpc.insecure_channel('172.20.0.2:50051') 
	//使用counters_pb2_grpc中的int_counterStub方法创建一个stub
	stub = counters_pb2_grpc.int_counterStub(channel) 
	//使用counters.proto文件中的GetCounter RPC,指定调用的参数interface,该参数即为GetRxPackets的输入参数
	response = stub.GetCounter(counters_pb2.RxpacketRequest(interface=server_int))
	return response

if __name__ == '__main__':
	response = GetRxPackets('eth0')
	print(response)
  1. 创建gRPC server端

在server端需要进行client端应用程序的逆过程,同样,在脚本文件中需要导入生成的protobuf代码,相应的counters_grpc_server.py如下:

//counter_grpc_server.py
from concurrent import futures
import time
import os
import grpc
import counters_pb2
import counters_pb2_grpc

class int_counter(counters_pb2_grpc.int_counterServicer):

	def GetCounter(self, request, context):
		// 将ifconfig命令的输出赋值给input变量,来自client的request消息包含步骤3中的interface
		input = os.popen('ifconfig ' + request.interface)
		// 利用列表解析遍历ifconfig的输出信息,并将包含RX packet字符串后的整数赋值给变量rxcounter
		rxcounter = int(''.join([x.split()[2] for x in input if 'RX packet' in x]))
		// 当通过RPC响应Client应用时,返回了两个参数,一是string字符串(Rx packet for ...),另一个是整数rxcounter
		return counters_pb2.RxpacketReply(
			message = 'Rx packet for %s: %i' %(request.interface, rxcounter))
	
def serve():
	server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
	counters_pb2_grpc.add_int_counterServicer_to_server(int_counter(), server)
	server.add_insecure_port('[::]:50051')
	server.start()
	print('gRPC server listening on port 50051')
	try:
		while True:
			time.sleep(99999)
	except KeyboardInterrupt:
		server.stop(0)

if __name__ == '__main__':
	serve()
	
  1. 开启server端服务

分别在server容器中开启server服务,在client容器中开启client应用:

root@grpc_server:/home/user# python counters_grpc_server.py

root@grpc_client:/home/user# python counters_grpc_client.py

将会在client端看到以下输出:

message: "Rx packets for eth0: 32"

以上就是Client端通过gRPC和Sever端连接,获得遥感(Telemetry)数据的简单实现过程,之后会介绍YANG数据模型和gNMI规范。

你可能感兴趣的:(openconfig)