本文作为码农学ODL系列的实战篇,首先介绍OpenFlow相关理论及其在ODL中的具体实现,接着讲述了基于ODL的应用程序总体开发流程,进而实现了流量限速的基础功能,最后验证了流量限速的基础功能。
一、理论基础
SDN中的流量限速可以基于OpenFlow协议来实现,其原理大致为:OpenFlow通过用户定义的流表(Flow Table)来匹配和处理报文,计量表项被流表项所引用,并为引用该计量表项的流表项提供报文限速的功能。由于大家对OpenFlow流表相对比较熟悉,而对计量表相对陌生。下面首先对计量表的基础知识进行详细介绍,然后给出OpenFlow协议在ODL中的具体实现。
1.Meter Table(计量表)
Meter Table是由多个Meter Enties构成,每个Meter Entry定义每个 Flow 的 meters。基于此结构,OpenFlow Switch可以实现各种简单的QoS功能,比如速率限制等,再结合每个port的queues,可以实现更加复杂的QoS框架,例如DiffServ。
一个meter可以衡量与它关联的数据包的速率,并进而可以控制其聚合速率。任何一个Flow Entry都可以在其Instructions Set里指定某一个Meter,从而控制与该Flow Entry能够成功匹配的数据包的聚合速率。
Meter Entry的具体结构如下:
每个Meter Entry都是由其Meter Identifier来唯一定位,详情如下:
(1) Meter Identifier:一个32位无符号整数,作为一个Meter Entry的唯一标识;
(2) Counters:被该Meter Entry处理过的数据包的统计量;
(3) Meter Bands:一个无序的Meter Band集合,每个Meter Band指明了带宽速率以及处理数据包的行为;每一个Meter Entry都可能有一个或者多个Meter Bands,每个Meter Band指明了带宽速率以及对数据包的处理行为。数据包基于其当前的速率会被其中一个Meter Band来处理,其筛选策略是选择那个定义的带宽速率略低于当前数据包的测量速率的Meter Band, 假若当前数据包的测试速率均低于任何一个Meter Band定义的带宽速率,那么不会筛选任何一个Meter Band,具体结构如下:
这里,每个Meter Band以其定义的Rate来唯一标识。每项具体说明如下:
(1) Band Type:定义了数据包的处理行为。
(2) Rate:Meter Band的唯一标识,定义了Band可以应用的最低速率。
(3) Counters:被该Meter Band处理过的数据包的统计量。
(4) Type specific arguments:某些Meter Band有一些额外的参数。
Band Type的类型有如下两种,它们都是可选的:
(1)drop:丢包,可以被用来实现一个rate limiter。
(2)dscp remark:增加数据包IP头DSCP域的丢弃优先级,可以被用来实现一个DiffServ仲裁器。
2.OpenFlow协议在ODL中的实现
在ODL中,OpenFlow的实现分为OpenFlowJava和OpenFlowPlugin两部分,其中OpenFlowJava负责面向南向设备完成OpenFlow协议的序列化、反序列化、端口监听以及消息分发,而OpenFlowPlugin负责完成OpenFlow协议的状态管理、会话管理、事务处理等,向SAL层提供服务。整体框架如下:
OpenFlowPlugin实现了OpenFlow协议,它提供了REST API接口,这里需要关注添加流表项、添加计量表项等接口;OpenFlowPlugin提供了SalFlowService和SalMeterService服务,在这两个服务接口中定义了插入、删除和更新流表项、计量表项的方法。因此,流量限速插件可以通过组合这些基础功能完成限速功能。SalFlowService接口定义如下:
SalMeterService接口定义如下:
二、总体开发流程
基于ODL的二次开发时,如果提供API的接口能够满足当前需求,那么只需基于REST API开发external System(外置式应用程序),如果提供的API接口不能满足当前需求,则需要进行Internal system(内置式应用程序)的开发,可以理解为插件。
基于REST API的外置式应用程序比较简单,正如《码农学ODL之SDN入门篇》中的介绍,在理解了业务之后,重点关注如何组织类之间的关系以及调用时序就可以了。本节重点介绍内置式应用程序的开发流程,大致流程如下图所示:
(1)生成项目骨架(Archetype)
Archetype是一个Maven项目模板工具包,使用Archetype来生成项目骨架,可以使得开发人员在开发新的应用程序时,使用与ODL风格一致的最佳实践方法。
例如,使用命令:
1 |
mvn archetype:generate -DarchetypeGroupId=org.opendaylight.controller -DarchetypeArtifactId=opendaylight-startup-archetype -DarchetypeRepository=http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ -DarchetypeCatalog=http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/archetype-catalog.xml |
参数artifactId的值设定为meterdemo后,生成的项目骨架大致为:
(2) 定义模型(model)
ODL中使用YANG进行模型的定义,其文件有两种格式,一种是来定义数据和接口,另一种是定义依赖注入、启动配置等信息,实践中可以根据具体业务需求修改已有或者新增model文件。
(3) 代码实现
YANG模型定义之后,通过YANG TOOLS可以自动生成部分代码,但对于Model对应的具体实现需要添加相关业务逻辑,如下图浅蓝色所示:
(4) 构建安装
构建应用程序,并将其安装在ODL中; 执行mvn clean install后,会在本地仓库以及ODL的distribution-karaf/target/assembly目录下生成相应的包;
(5) 测试验证
代码编译打包、加载完成后,最后一步就是测试一下应用程序的业务逻辑,验证是否满足项目的需求。
三、流量限速实现
1.实现原理
流量限速采用内置式应用的开发方式,对外提供流量限速REST API,该API提供switch-id、band-type、src-port、dst-port、limited-rate和burst-size等6个参数,其中band-type默认为drop,调用方可以只设置其他5个参数,并下发流表项、计量表项(两者关联)到交换机,就可以实现端到端的流量限速。每个参数的详细含义如下:
(1) switch-id是在拓扑中可以查到交换机的唯一标识;
(2) src-port 是交换机APP流的入端口;
(3) dst-port 是交换机APP流的出端口;
(4) limited-rate 是要限制的速率大小;
(5) burst-size是触发限速功能值,当数据包达到这个值的时候,会触发限速功能,流表会执行限速。
2.逻辑框架
通过OpenFlow协议在ODL中的实现这一章节的分析,我们知道OpenFlowPlugin提供了相流表和计量表相应的REST API接口,同时,SalFlowService和SalMeterService也提供了相应的接口,从业务需求来讲,外置式应用程序和内置式应用程序都可以实现流量限速;从技术上来讲,开发内置式应用程序难度相对大些,本着学习的目的,本文开发内置式应用程序,提供对外的REST API接口,实现流程限速。其逻辑框架如下图所示:
另外,SDN控制器存在两种工作模式:主动和被动。主动模式下,控制器将流表信息一次性下发到交换机;被动模式下,在数据平面收到新的数据包时,控制器才将相关流表信息下发到交换机。通常情况下,往往预先下发部分流表信息。本文采用主动下发流表的方式。
3.具体实现
结合基于ODL的应用程序总体开发流程和《码农学ODL之Toaster代码解析》两部分内容,本节重点关注定义Yang模型、实现流量限速服务和应用程序与MD-SAL关联等内容,详情如下:
3.1 定义Yang模型
定义meterdemo.yang,该文件定义在meterdemo-api/src/main/yang/目录下,其目的是定义简单rpc操作,定义交换机ID、入端口、出端口、限速值,触发限速值等参数。
1 2 3 4 5 6 7 8 9 10 11 |
module meterdemo { yang-version 1; namespace "urn:opendaylight:params:xml:ns:yang:meterdemo"; prefix "meterdemo"; revision "2016-08-21" { description "Initial revision of meterdemo model"; } rpc process-meter { //rpc input: 指定交换机ID,源目的端口,限速值,触发限速值;下发相应Flow-Table及Meter-Table output:Meter-Table Flow-Table 下发状态 } |
执行mvn clean install,编译meterdemo 项目生成相应builder及服务接口,生成的代码如下所示:
其中,MeterdemoService定义如下:
1 2 3 4 |
public interface MeterdemoService extends RpcService { Future<RpcResult<ProcessMeterOutput>> processMeter(ProcessMeterInput input); } |
3.2 实现流量限速服务
实现流量限速服务,需要实现MeterdemoService,其业务逻辑为:调用SalFlowService和SalFMeterService,其中,SalFlowService 提供下发流表项到指定交换机的基础功能,SalMeterService 提供下发计量表项到指定交换机的基础功能。其代码大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public MeterdemoServiceImpl(SalFlowService salFlowService, SalMeterService salMeterService) { this.salFlowService = salFlowService; this.salMeterService = salMeterService; } @Override public Future<RpcResult<ProcessMeterOutput>> processMeter(ProcessMeterInput input) { ProcessMeterOutputBuilder outputBuilder = new ProcessMeterOutputBuilder(); Long meterId = meterIdInc.getAndIncrement(); //添加单条Meter-Table addMeter(input.getSwitchId(), input.getLimitedRate().longValue(),input.getBurstSize().longValue(), meterId); } //添加从源端口到目的端口的单条Flow-Table和Meter-Table关联 addFlow(input.getSwitchId(),input.getSrcPort(),input.getDstPort(), meterId) |
其中,addMeter方法如下:
1 2 3 4 5 6 |
//私有方法,实现具体的Meter-Table下发 private Future<RpcResult<AddMeterOutput>> addMeter(String switchId, longrate, longburstSize, long meterId) { //构造MeterTable 参考ODL OpenFlowPlugin 下发Meter-Table相关代码 //下发Meter-Table return salMeterService.addMeter(addMeterBuilder.build()); } |
addFlow方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//私有方法,实现具体的Flow-Table 下发,具体可参考L2-Switch 流表下发代码 private Future<RpcResult<AddFlowOutput>> addFlow(String switchId, intinPort, intoutPort, longmeterId) { //构造Flow-Table 参考ODL OpenFlowPlugin 下发Flow-Table相关代码 FlowBuilder flowBuilder = new FlowBuilder().setTableIID(DEFAULT_TABLD_ID).setFlowName(“meter”); //关联Flow-Table Meter-Table Instruction applyMeterInstruction = new InstructionBuilder() .setOrder(1) .setInstruction(new MeterCaseBuilder() .setMeter(new org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.meter._case.MeterBuilder().setMeterId(new MeterId(meterId)).build()).build()).build(); instructionList.add(applyMeterInstruction); //下发FlowTable return salFlowService.addFlow(addFlowInputBuilder.build()); } |
3.3 应用程序与MD-SAL关联
定义meterdemo-impl.yang,该文件在meterdemo/src/main/yang/目录下,其目的是扩展md-sal config data节点;引用binding-broker-osgi-registry注册服务,注册meterdemo rpc。其Yang定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
module meterdemo-impl { yang-version 1; namespace "urn:opendaylight:params:xml:ns:yang:meterdemo:impl"; prefix "meterdemo-impl"; import config { prefix config; revision-date 2013-04-05; } import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;} } identity meterdemo { base config:module-type; config:java-name-prefix Meterdemo; } //扩展md-sal datastore config节点 ,类型 meterdemo augment "/config:modules/config:module/config:configuration" { case meterdemo { when "/config:modules/config:module/config:type = 'meterdemo'"; container broker { uses config:service-ref { refine type { mandatory true; config:required-identity md-sal-binding:binding-broker-osgi-registry; } } } } } } |
执行mvn clean install,编译meterdemo项目,生成的代码如下所示:
流量限速内置应用程序与MD-SAL关联代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
publicclass MeterdemoProvider implements BindingAwareProvider, AutoCloseable { privatestaticfinal Logger LOG = LoggerFactory.getLogger(MeterdemoProvider.class); private BindingAwareBroker.RpcRegistration<MeterdemoService> meterdemoService; @Override Publicvoid onSessionInitiated(ProviderContext session) { SalFlowService salFlowService = session.getRpcService(SalFlowService.class); SalMeterService salMeterService = session.getRpcService(SalMeterService.class); meterdemoService = session.addRpcImplementation(MeterdemoService.class, new MeterdemoServiceImpl(salFlowService, salMeterService)); } public class MeterdemoModule extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.meterdemo.impl.rev141210.AbstractMeterdemoModule { @Override public java.lang.AutoCloseable createInstance() { MeterdemoProvider provider = new MeterdemoProvider(); getBrokerDependency().registerProvider(provider); return provider; } } |
四、测试验证
1.环境预设
测试环境使用品科物理交换机,通过ODL下发单条流表项并关联单条计量表项(源端口为3,目的端口为7);使用iperf打流工具沿192.168.5.7 -> 192.168.5.8 方向打流,观察带宽值,判断是否达到预设限速效果,如下图所示:
2.测试验证
(1) 启动ODL:
启动ODL,加载meterdemo plugin后, 通过浏览器访问如下URL地址: http://{ip}:8181/index.html#/yangui/index
(2) 下发限流请求:
设置请求参数值(源端口为3,目的端口为7,限速为7000,触发限速值为100,band-type默认为drop),通过ODL向交换机下发限流请求;
(3) 查看交换机流表项及计量表项:
以SSH的方式登录交换机,计量表项显示如下:
流表项显示如下:
(4) 打流并验证
通过iperf进行打流,观察实验(限速前,限速后)带宽。通过如下2个图的对比可以看出带宽被限制在rate范围内。
iperf客户端查询结果如下:
iperf服务端查询结果如下:
作者:SDNLAB--SDN/NFV开发团队
简介:致力于SDN/NFV等前沿技术的研究、应用与实践,已研发推出UMS网络流量监控、SDN智能流量调度、NFV管理编排等产品。专注为高校、企业、政府以及电信运营商等客户提供定制化及个性化的SDN/NFV系统开发服务。