中兴通讯技术丛书
点击阅读第二章
点击阅读第三章
ODL技术内幕:架构设计与实现原理
耿兴元 著
第一部分
基础环境篇
第1章
阅读源代码前的准备
OpenDaylight(简称ODL)是在2013年由18家网络巨头发起成立的,旨在推动SDN发展及促进网络领域创新的开源控制器平台项目。ODL项目的目标是成为SDN领域的开发、运行、创新的框架和平台。开源项目自有其天生的优势和劣势,也必须遵循自身的发展演进的规律。开源项目优势可总结为具有兼容并包的框架性设计,聚集了众多贡献者大胆创新的思想,版本迭代快速等。开源项目的劣势也很明显,那就是开源项目一般缺乏系统性、完善的文档,部署、升级和运维监控等方面考虑的也都有所欠缺,所以自身很难提供针对具体场景的端到端的商用解决方案。另外,对于一个比较活跃的开源项目,需要5~7年才能做到框架的成熟和稳定。ODL项目成立至今已有6年多,我们可以说其核心框架已经稳定和成熟了。因此,理解并掌握ODL的最新核心框架的设计与实现原理,对于我们利用ODL这个框架和平台进行商用产品的研发是有很大帮助的。
本章主要为后续章节做准备,将指导大家搭建 ODL的编译开发环境,也会向大家简单介绍ODL的诸多子项目以及这些项目的组织管理方式,并对ODL核心的MD-SAL框架的设计目标和设计原则做一个简单的介绍,让大家对ODL项目及其核心架构有一个整体的了解。
1.1 ODL项目介绍
ODL项目成立之初,发起成立该项目的众多网络巨头都拿出了自己在SDN领域或网络虚拟化方面的一些项目代码贡献到ODL社区,包括Cisco的OnePk(ODL中的controller子项目)、Big Switch的控制器与网络虚拟化项目(ODL中的OSCP子项目)、IBM的DOVE(ODL中的OpenDove子项目)、Radware的安全防御系统(ODL中的Defence4All子项目)、NEC的Virtual Tenent Network(ODL中VTN子项目的)等。这些项目本身都是由各公司自己开发的,有些还是已经商用的项目。虽然这些项目本身质量还可以,但是因为缺乏统一的框架和设计思路,有些项目还具有竞争性质,导致这些项目没法组合成一个有机的整体,因此,我们看到的ODL的初始发布版本(氢版本),就是一个拼凑起来的大杂烩。随着近年来的不断完善,ODL逐渐形成了统一的架构和合理的项目层次。
1.1.1 ODL框架之争
在最初的ODL众多子项目中,Cisco主导的controller子项目和Big Switch主导的OSCP项目代表了SDN控制器框架设计的两种思路,二者属于竞争关系。
controller项目中,基于平台化的设计思路,提出了业务抽象层(Service Abstraction Layer,SAL)的概念,把控制器分为南向(SB)协议插件、北向(NB)业务/应用插件和SAL三层。通过SAL层,实现了多种南向协议插件与多样化的业务应用的解耦,这种设计借鉴了早期的SDN开源控制器Beacon的基于OSGi的模块化框架设计,符合ONF提出的典型的SDN三层架构,每一层都暴露大量的API供不同层次的业务应用进行调用,使系统具有很强的扩展性和灵活性。
OSCP项目中,主要采用了产品化的设计思路,南向协议绑定在OpenFlow上,提供集成度高的、功能比较完善的网络基础功能管理,但这将导致整个系统围绕着OpenFlow协议紧紧地耦合在一起,限制了控制器自身的扩展性与适用性。
当然,我们知道,Cisco的思路在ODL社区最终胜出,成为ODL的核心框架。而Big Switch与Cisco在ODL社区角力失败也导致了其在ODL社区运作了还不到3个月的时间就退出了。
1.1.2 SAL的演进
最初的SAL是以AD-SAL(API-Driven SAL)为主的,也就是需要分别定义南向插件的Java编程接口(API)和业务应用的Java编程接口(API),并需要为两种接口做大量的适配编码。另外,北向的REST接口也要手工定义。显而易见的,作为一个开放的开发平台来说,增加一个新的插件功能,就需要通过手工编码来定义SAL API和适配代码,使其具有很大局限性。一方面API的定义非常困难,因为这需要非常专业的网络领域的知识,还要考虑规范性、通用性和扩展性;另一方面,大量的手工编码对于开发者来说非常不友好。因此,从ODL的氦(Hellium)版本和锂(Lithium)版本开始,一直到氟(Fluorine)版本,MD-SAL(Model-Driven SAL)架构逐步发展并成熟,而AD-SAL从铍(Berryllium)版本即被完全废弃。截至现在,ODL社区加入了越来越多的基于MD-SAL框架设计的南向协议类的项目和应用类项目(几十个),而ODL成立时建立的一些不太符合该设计思路的项目,比如OSCP、Defence4All、OpenDove等现在已经被社区归档,不再继续维护。
1.1.3 ODL的子项目及分类
MD-SAL架构采用YANG语言作为数据及接口的建模语言,通过YangTools工具提供了编译期数据模型与接口的解析和代码的自动生成,采用Binding Broker、Binding-Inde-pendent Broker两套接口实现了运行期的数据模型与接口的适配转换,简化并规范了南向插件与业务应用间调用接口的定义,为南向插件和业务应用的开发者提供了统一的开发模式。MD-SAL框架的主体代码原本在controller和yangtools两个项目中,特别的是,controller项目最初不仅包含SAL框架,还包括配置子系统、netconf/restconf、版本公共配置及版本打包、项目模板等功能。随着ODL项目的发展演进,这些功能有的单独成立子项目(mdsal、odlparent、netconf/restconf、archetypes),有的被废弃(配置子系统、AD-SAL),当前仍保留在controller项目中的功能代码主要是ODL的分布式集群功能(分布式datastore和remoterpc)和blueprint扩展。以上controller、mdsal、odlparent、netconf/restconf等子项目加上yangtools项目基本上就构成了ODL的核心框架,再加上ODL的鉴权框架AAA项目,这些子项目就是ODL的核心项目。除了决定ODL基础架构的这些核心项目,ODL的项目中还包括协议类项目、业务应用类项目及支持类项目。协议类项目包括多种南向协议插件项目如OpenFlow、OVSDB、NETCONF、BGP、BMP、PCEP、LISP、SNMP、P4、SXP、OCP、P4、Telemetry等,还包括北向的RESTCONF、NEMO Intent等。业务应用类项目包括NetVirt、COE、FaaS、BIER APP、DetNet、SFC、Transport PCE、IOT等,支持类项目包括Documentation、Inte-gration、RelEng等。图1-1显示了ODL社区现在的活跃的项目及项目间的依赖关系。
因为ODL社区中不断接受申请成立新的子项目,原来的子项目也会根据情况进行调整,甚至被废弃而归档,因此图1-1中的项目不一定与最新的ODL子项目一一对应,但从几个核心项目来说,图1-1还算准确。
图1-1 ODL子项目及其依赖关系图
1.1.4 ODL项目的管理
ODL的项目除了支撑类项目使用的Python、Shell脚本语言,其他大部分项目都是使用Java语言。采用Java语言作为开发语言的项目,大量的开源第三方组件及项目间的依赖管理是一件令人头疼的事情,而ODL社区借助Maven这款优秀的项目管理工具,实现了ODL项目的依赖下载、编译、构建、测试、打包、部署等一系列功能。
Maven工具通过pom配置文件来声明项目的依赖和编译构建选项。对于一个ODL的项目,只要其根目录下有pom文件,执行如下命令,即可实现项目的第三方组件的依赖下载、编译、测试、打包和安装到本地仓库的功能。
mvn clean install
当然,要想执行上述命令,必须先安装JDK和Maven,并正确配置环境变量。1.2节会简单讲解安装ODL编译构建环境的过程。
1.2 搭建ODL编译构建环境
操作系统推荐使用Linux的发行版本Ubuntu或者Mac OS X,如果选择Windows的话,需要注意有些ODL项目是编译不过的。
1.2.1 安装JDK
JDK(Java Development Kit)是Java语言的软件开发工具,JDK是整个Java语言开发的核心,它包含了Java的运行环境、Java工具和Java基础的类库。ODL的大部分项目是采用Java语言编写的,因此要编译构建ODL项目,首先要安装对应的JDK版本。截至目前,ODL已经发布了9个大的版本,编译前3个发布版本(氢、氦、锂)的代码需要安装JDK 7版本,编译后6个版本(铍、硼、碳、氮、氧、氟)的代码需要安装JDK 8版本。ODL社区最新计划从第10个版本(也就是钠版本)开始,采用JDK 11版本(兼容JDK 8)。下面以JDK 8版本为例介绍其安装和配置过程,其他版本的JDK安装参考Oracle官方文档即可。
1. JDK下载安装
JDK 8下载地址:
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
Mac OS X或者Windows操作系统,请下载对应操作系统类型的安装包,下载后安装即可。
Linux操作系统可以下载JDK 8压缩包解压到某个目录下,也可以采用下面的命令直接安装。
Fedora:
sudo dnf install java-1.8.0-openjdk java-1.8.0-openjdk-devel
Ubuntu:
sudo apt-get install openjdk-8-jdk
安装后,在控制台终端执行命令java –version验证JDK是否安装成功。安装成功会打印如下信息:
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
2.设置环境变量
对于Windows操作系统,按“我的电脑→属性→高级→环境变量→用户变量→新建(N)”路径添加环境变量JAVA_HOME和JAVA_TOOL_OPTIONS,如图1-2、图1-3所示。
图1-2 JAVA_HOME环境变量设置
图1-3 JAVA_TOOL_OPTIONS环境变量设置
在Path环境变量中加入%JAVA_HOME%bin
对于Linux或Mac OS X操作系统,通过配置文件~/.bash_profile或/etc/profile配置环境变量。
export JAVA_HOME={YOUR_JDK_INSTALLED_DIR}
export PATH=$JAVA_HOME/bin:$PATH
1.2.2 安装及配置Maven
1. Maven安装
Maven下载地址(推荐安装最新的Maven 3.6.0,编译ODL最新版本代码不得低于3.5.2):http://maven.apache.org/download.cgi,下载后解压到某个目录即可。
解压Maven后,在/etc/profile中配置环境变量MAVEN_HOME,在PATH下增加$MAVEN_HOME/bin路径。
export MAVEN_HOME={WHERE_YOU_UNZIPPED_MAVEN}/apache-maven-{MVN_VERSION}
export PATH=$MAVEN_HOME/bin:$PATH
export MAVEN_OPTS="-Xmx1024m"
Windows操作系统请按照1.2.1的方式增加这3个环境变量。
使用参数MAVEN_OPTS设置Maven工具构建项目时,设置Java虚拟机最大可用内存。构建ODL的项目时,Java默认的最大可用内存是不够的,需要把这个值设置得大一些,至少1024M。如果开发机器允许,这个参数还可以设置得更大一些。
执行命令mvn –v验证Maven是否成功。成功会显示如下内容:
Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-25T03: 49:05+08:00)
Maven home: /usr/share/maven
Java version: 1.8.0_161, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.x86_64/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-693.2.2.el7.x86_64", arch: "amd64", family: "unix"
2. Maven配置
ODL维护了独立于Maven中央仓库的一个Maven仓库,如果不修改Maven默认的settings.xml,是无法访问ODL发布的组件的。要编译构建ODL的项目或者基于ODL开发自己的应用,必须要依赖ODL发布的组件,因此必须把https://github.com/opendaylight/odlparent/blob/master/settings.xml复制到~/.m2/settings.xml或者覆盖$MAVEN_HOME/conf目录中的settings.xml。
如果你是通过代理上网的,那还要在settings.xml里设置上网代理,如代码清单1-1所示。
代码清单1-1 Maven上网代理配置
详细说明可参考http://maven.apache.org/guides/mini/guide-proxies.html。
1.3 阅读和调试ODL源代码
安装好JDK与Maven后,就可以对ODL项目进行编译构建了。如果想方便地阅读和调试ODL项目源码,安装一个好用的集成开发(IDE)工具是十分必要的。推荐安装IntelliJ IDEA这款IDE工具,使用其阅读和调试代码非常方便。
1.3.1 ODL项目源码下载
ODL是通过Git仓库管理所有项目的源码,ODL官方仓库地址https://git.opendaylight.org。
Linux操作系统建议先安装git工具。
Fedora:
sudo dnf install git
Ubuntu:
sudo apt-get install git-core
安装好git工具后,通过浏览器打开https://git.opendaylight.org,点击Projects→List可以看到ODL所有的子项目,选择你感兴趣的项目,比如AAA。在General标签下,可以找到通过git工具克隆AAA项目源码库的命令,如图1-4所示。
图1-4 AAA项目
然后复制命令git clone https://git.opendaylight.org/gerrit/aaa执行,这样就可以把AAA项目的源码克隆到本地。
进入AAA目录,执行命令git branch –a查看该项目所有的分支,执行命令git tag –list查看该项目所有的tag。
如果想查看某一分支或者tag的源码,执行git checkout [branch or tag]:
git checkout release/fluorine-sr2
即把本地代码切换成最新发布的Fluorine-SR2版本。
你也可以直接通过ODL在GitHub上的镜像库(https://www.github.com/opendaylight)下载各项目的源码。打开链接后,选择感兴趣的项目,在branch下拉菜单里选择分支或者tag,然后点击Clone or download→Download ZIP,下载源码包后解压即可。
进入到AAA目录下执行命令mvn clean install即可构建该项目。
1.3.2 IntelliJ IDEA安装
进入官网https://www.jetbrains.com/idea/download,选择适合版本下载IntelliJ IDEA。
IntelliJ IDEA分为社区免费版和商业版,如果财力允许,可以选择安装商业版。一般来说,社区免费版也够用了。
读者可以按照提示或者参考网上的安装指导完成IntelliJ IDEA的安装。
1.3.3 IntelliJ IDEA调试ODL的项目源码
要通过IntelliJ IDEA调试跟踪ODL子项目的源码,首先要下载ODL的某个发行版本并带debug参数启动该版本。ODL版本下载地址https://docs.opendaylight.org/en/latest/downloads.html,请选择合适的ODL发布版本下载。下载后解压到某个目录,进入解压目录,通过命令./bin/karaf debug启动ODL,在karaf控制台通过feature install命令安装该子项目相关的feature,这样才能通过IntelliJ IDEA调试该版本源代码。
确保该子项目源码启动的是上述ODL版本tag的源码,然后在IDEA里直接导入该子项目,也可以在该子项目的根目录执行mvn idea:idea生成IDEA工程。用IDEA打开后缀为.ipr的工程文件,推荐用mvn idea:idea的方式,因为其可以提前下载依赖并发现构建的问题。在IDEA里打开该子项目工程后,依次选择Run→Debug→Edit Configurations,然后选择列表中的Remote方式,在Host处填写ODL运行的服务器的IP,Port为5005,如图1-5所示。最后点击图1-5中的Debug按钮即可对ODL的源码进行调试跟踪。
图1-5 调试ODL项目源码的配置
当然,阅读调试ODL源码的目的不仅仅是为了查找Bug、定位问题。分析源代码的实现流程和设计思路也有助于我们更好地理解ODL架构设计和实现原理,这也是本书的主旨所在。
1.4 ODL设计目标
SDN(Software Defined Network,软件定义网络)的运动来自一个简单的问题:为什么网络设备不应像其他计算平台一样可编程?SDN的设计理念通过分解传统的垂直集成的网络设备堆栈,并将控制平面重构为独立于网络设备的操作系统,可以实现如下几个长远目标:
- 来自不同供应商的不同物理和虚拟设备类型的互操作性。
- 提供网络流量从源到目的的可视性。
- 面向所有设备的通用的管理框架。
- 可根据用户需求塑造网络行为的可编程性。
- 基于策略的自动化。
ODL作为SDN设计理念中控制与管理面的开发及运行平台(网络操作系统),是迄今为止这个新堆栈中最大和最成熟的项目,逐渐成为新开放网络生态系统的核心组件。
ODL作为一个SDN控制器运行与开发平台,在架构设计上考虑了如下关键需求。
- 灵活性:SDN控制器必须能容纳大量的各类型应用。同时,控制器应用应该是使用通用的框架和编程模型,提供一致的API给客户端。这对于发现并解决故障、系统集成、组合多种应用为更高级的编排流都是十分重要的。
- 开发过程规模化:控制器架构必须允许插件、业务组件、应用能相互独立进行开发,能够灵活地选择功能特性进行集成。
- 组件的运行时安装与卸载:控制器必须能够在运行时安装新的协议、业务及应用插件。控制器的基础架构需要适应动态安装的插件或从设备动态中发现的数据模型,运行时的扩展性允许控制器适应网络的变化(新设备或新网络特性),避免传统EMS、NMS冗长的发布周期。
- 性能与规模:控制器应该能够在多样化的环境中,使得承担不同的负载/应用都运行良好。当然,性能不应该通过在模块化上花费大量代价来获得。控制器架构应该被允许在集群、云环境中进行水平扩展,平台需要能为其提供一致性的集群支持。
为了支持SDN应用的开发,控制器也应该提供满足如下需求的应用开发环境。 - 使用领域模型语言描述内部和外部的系统行为,会促进开发人员和网络专家的协作,方便系统集成。领域模型语言和代码生成工具应该提供API和协议的快速进化(敏捷)。控制器使用的领域语言、技术、工具对于一些通用的网络概念,比如业务、服务链、用户管理和策略等都要是可用的。
- 控制器使用的模型工具应该与设备的模型工具一致,这样控制器和设备就可以使用通用的工具链,设备模型在控制器中也可以被重用,使用这些模型的控制器应用/插件与设备之间即可实现无缝对接。工具链也应该支持业务和设备的模型间的适配代码的生成。
1.5 ODL总体架构
了解了ODL平台的设计背景和设计目标,会帮助我们理解ODL的整体架构。考虑到平台必须灵活地支持多种南向协议插件,支持多样化的业务及应用,支持运行时的组件安装与卸载,那么,整个平台就必须是模块化的架构设计,模块间要尽量松耦合,模块间交互要有统一的方式和标准。基于此,ODL所有组件都需要遵循Java平台事实上的动态模块化规范OSGi进行设计,直接基于Karaf这个强大的OSGi容器来提供组件的部署和运行环境。当然,OSGi规范的实现框架在Karaf的配置文件中可以配置为felix或者equinox。我们可以在解压的ODL发布版本的配置文件/etc/config.properties和/etc/custom.properties中看到如下相关配置:
karaf.framework.equinox=mvn:org.eclipse.platform/org.eclipse.osgi/3.12.100
karaf.framework.felix=mvn:org.apache.felix/org.apache.felix.framework/5.6.10
Use Equinox as default OSGi Framework Implementation
karaf.framework=equinox
从JDK 9开始,模块化已是Java提供的一个原生特性。截至ODL第9个发布版本,ODL还没有基于JDK 9及JDK 9以后的版本进行构建,因此其模块化仍然是遵循OSGi规范设计的。但ODL社区计划在第10个发布版本中基于JDK 11进行构建。
ODL把被控制和管理的网络抽象为一个以消息驱动的巨大的状态机,因此ODL架构中的消息机制与状态保存机制就成了整体架构中最基础的服务设施。为了简化并规范化消息与状态数据的定义,ODL社区引入YANG语言作为消息与状态数据的模型语言。在ODL中,通过YANG语言驱动设计的这些基础服务设施被称为模型驱动的服务抽象层(MD-SAL,Model-Driven Service Abstraction Layer),MD-SAL是ODL平台整体架构的核心,为南向协议插件和业务应用提供统一的服务调用接口。具体来说,ODL的MD-SAL提供了RPC、Notification、数据变更通知这3种消息机制,同时提供了DataStore来保存设备与业务的配置和状态(Config & Operational两种类的库)。如图1-6 Platform部分所示。
图1-6 ODL总体架构
由图1-6可见,MD-SAL是ODL整体架构的平台部分,提供了多种模块间的调用与交互机制。比较典型的包括:1)RPC提供了消费者与提供者之间一对一的调用路由机制;2)Notification提供了消息的订阅发布机制;3)DataStore提供了配置与状态数据的保存和查找机制,并提供了在集群环境中的数据细粒度分片与一致性保证。从MD-SAL架构来说,南向协议插件和业务/北向应用的生命周期都是一样的,每个南向协议插件和业务/应用都是一个OSGi的Bundle,遵循同样的设计思路,围绕MD-SAL架构提供的基础服务,通过YANG模型来定义其交互的接口标准。这样,无论是南向协议还是业务应用,都可以被看作基于MD-SAL架构的一个扩展插件,如图1-7所示。
图1-7 基于MD-SAL的南向协议与业务应用插件
ODL通过YangTools实现了YANG模型的解析和自动生成接口代码,南向协议/业务应用插件只需要定义出YANG模型,MD-SAL不需要包含任何插件特定的代码和API,对所有加载到控制器的南向协议/业务应用插件都提供了通用的处理机制。通过YangTools工具,使得插件间的调用接口、RESTCONF接口都由YANG模型统一定义并自动生成。通过MD-SAL,实现了南向协议/业务应用插件间接口调用的运行时适配。
1.6 本章小结
本章主要是为了下面更深入地理解ODL架构的设计原理做准备。通过本章的介绍我们应该学会搭建ODL的编译调试环境,理解MD-SAL是ODL架构的核心。当然,本章也提到ODL的众多子项目都是通过Maven工具进行管理的,第2章将介绍ODL社区在项目管理上碰到的若干问题以及相应的解决方案。