在SDN发展的历史潮流中,OpenFlow是先于SDN出现的,也就是说先有了OpenFlow,才在OpenFlow基础上提炼出SDN的概念,那么到达什么是OpenFlow呢?
SDN是一种网络架构的理念,是一个框架,不规定任何具体的技术,而OpenFlow是一个具体的协议,这个协议实现了SDN这个框架中的南向接口,而且除了OpenFlow也可能存在别的同样功能的协议来完成相似的工作,总的来说,SDN是独一无二的,但是OpenFlow有竞争者,不是SDN的全部,OpenFlow是现在SDN框架内最有影响力的一个协议。
从SDN的架构图中知道,控制面controller跟数据转发面之间,通过标准的南向接口进行通信,OpenFlow就是这样一种用于controller和网络设备之间通信,被controller用来控制网络设备,网络设备反馈信心给controller的标准化的南向接口,并且OpenFlow还规定了网络设备对报文的转发和编辑方式,不同于传统的路由和交换设备。
OpenFlow的维护者是ONF,但是第一版的设计者是斯坦福大学的学生,他们搭建的交换机是基于Net-FPGA的,有理由相信设计者没有丰富的交换机系统控制面设计经验,更没有丰富的工业级芯片设计经验,主要的经验是网络的使用外加一些学术研究,从现有的OpenFlow的标准来看,实现性质非常明显,过于理想化,特别是对当前的商业交换芯片有很大的设计和成本上的挑战。下图为标准的OpenFlow controller和OpenFlow交换机的网络架构。
1 交换机转发面详解
2 controller和交换机之间消息
3 OpenFlow channel
4 controller角色和选举
5 OpenFlow系统性能指标
6 OpenFlow controller和交换机工作流程
7 对OpenFlow标准的总结
一、交换机转发面详解
OpenFlow协议涉及两个网络元素:OpenFlow Controller(控制器)和OpenFlowSwitch (交换机),OpenFlow协议有一部分运行在Controller上,另一部分运行在Switch上。这个协议具体定义了交换机转发面的功能部件, Controller如何来控制Switch以及Switch如何来反馈Controller的一系列过程,以及两者之间通信的消息类型和消息格式,同时还有一系列的标准术语。
OpenFlow交换芯片(转发面内部)可以认为在逻辑上分成两部分:端口port和流表flow table。跟controller通信的信道controller channel可以认为是特殊的端口,一个交换机有很多端口,也可以有很多级流表。
在 OpenFlow协议中, Controller通过一套标准的消息接口,告诉交换机,报文从哪些Port进来,就要去查哪张流表,匹配到一条流表项(Flow Entry)之后,就要去执行这条流表项所规定的指令,然后要么直接转发出去或者丢弃,要么继续去查找下一个指定的流表(由匹配到的这条流表项来指定),然后重复这个过程,直到报文被丢弃或者转发出去。
流(Flow): 流不仅是OpenFlow也是数据通信网络中一个很重要的概念所谓的流,就是指在一段时间内,经过同一个网络的一系列具有相同属性的顺序发送的报文集合。所谓相同属性,这并不固定,取决于应用场景。比如具有相同的源ip和目的ip,或者都是TCP报文,并且源端口,目标端口都一致。
流表(flow table) 流表就是芯片中的转发表,每张流表都由很多条流表项组成,比如一张流表有16K,那么这张流表就有16K流表项。
流表项(flow entry): 流表项是流表的最小单位,每条流表项对应了网络中传输的一条流,流表项是OpenFlow中最核心的元素,根据OpenFlow标准,每条流表项的组成部分如图:
match fields匹配字段 priority优先级 counter 计数器
instruction指令 timeout超时时间 cookie 附属属性
流表项的组成部分是controller和交换机之间传输数据结构,是对流表项的逻辑描述,并不是与芯片转发表中的实际字段一一对应。流表查找的过程通俗来讲就是对进来的报文,用流表指定的字段去匹配查找,如果匹配到一条流表项,就执行这条流表项所规定的指令。
匹配字段match fields
包括报文本身的信息,比如源MAC地址,VLAN信息等以及跟报文关联的字段,比如报文进来的port,前一张流表传过来的属性数据。同一张流表里面不同的流表项的匹配字段可以不一致,也可以相同。
优先级priority
报文在流表中进行匹配查找是自上而下顺序查找的,放在前面就可以被优先匹配到,优先级是用来标志流表项之间的顺序关系的,优先级相同的流表项是平等的,没有顺序关系,controller往交换机下发流表项的时候,用优先级告诉交换机该流表项在流表中存放的相对位置。
计数器counter
计数器是管理员用来观察监控网络负载情况的工具,原则上每条流表项都有一个对应的计数器,来表示属于这条流的报文已经收到了多少个以及各种其他统计数据,比如多少字节,多少错误的包等。
指令instruction
OpenFlow定义的指令有好几种,具体如下:
meter——用来测量该flow的速率并执行相应的动作。每个meter包含几个band,每个band对应一个rate速率和动作,band的意思就是如果测量的flow的速率超过了指定的rate,就执行相应的动作。可以是drop或者dscp remark(改写IP报头中的dscp值)。
apply-action——对报文执行一个action list动作列表里面指定的所有action,这些action执行的结果可能影响也可以不影响下一级流表查找。比如每条流都出一个counter,立即对匹配该流的报文数量进行统计。
write-action——并不立即对报文执行动作,而是把一个action list里面的多个action放到一个action set动作集合里面。等到所有流表都处理完了,再一次性处理这个集合里面的所有action。如果两个不同的流所放的action有冲突,那么后面的覆盖前面的。如果只支持单流表的话这个时候就相当于apply-action。
clear-action——如果某条流想把前面所有流表处理后产生的action set都消除掉,就需要执行这条指令。比如前面一个流表说丢弃该报文,当前流表要把报文重定向到一个端口,但是前面已经丢弃了这个报文了,为了不丢弃,就要先把前面的动作清除掉,这个时候就需要clear-action。只支持单流表的时候这个指令没有意义。
write-metadata——metadata为描述信息,简单理解,就是把代表一条流的独一无二的特征ID,用来在多级流表之间传递以达到关联多级流表的目的。举例来说,有大量的外部主机(比如1000台)通过一个OpenFlow交换机访问一个网络里面的server。管理员想监控外部发进来的每一个连接,最直接的办法就是安装1000条匹配iada+ipsa的流,每条流有个30个bit的counter,占用94000(1000*(32+32+30))bits的memory。如果换个思路,用两张流表,第一张匹配ipda,第二张匹配ipsa,然后再第一张流表的每条流出一个6个bit的ID作为metadata来标识一个ipda,这个ID传到第二张流表跟ipsa一起参与匹配查找,第二张流表出30个bit的counter,这样一共消耗的memory64*(32+6)+1000*(32+30+6)=70432bit。换句话说,有了metadata和多级流表,它就像一级流表的M*N的memory消耗,变成了M+N。那么write-metadata是什么意思呢?这个指令只有在三级或者以上流表的时候才有意义。 原理如下:第一级流表中某个流表项flow1出了一个metadata,假设是0x12340000,传到了第二级流表,第二级流表有100条流表项是通过这个metadata跟前面的那个流表项flow1关联,然后这100条流表项每个都有自己的ID(子metadata),它们就用自己的子metadata覆盖了前面metadata中的低16bit。到了第三级流表的时候,这个metadata里面就包含了前面两级流表中两条流表项的基因。
goto table——继续下一级指定流表的处理。这个指令是所有指令中唯一required既要求也必须支持的指令,其他都是可选的,同理,单流表情况下指令毫无意义。
超时时间timeout
每条流表项都可以被老化, Timeout就是表示该流的老化时间。 Openflow定义了两种老化时间, hard timeout和idle timeout,前者表示从该流表项创建开始,到了这么长时间之后,无条件删除:后者则表示如果在这么长时间内没有任何报文匹配过该流表项,那就把它删除,前者可以靠软件来做,后者必须有硬件协助。
附属属性cookie
Cookie是被Controller向Switch来传递流表项相关的操作信息的,比如修改Flow、删除Flow等。这个属性不会在报文转发的时候被使用,仅仅用于Controller和交换机之间传递消息。
动作(Action): Action是应用到一个报文上的最小原子操作,宏观来看包括两大类,报文编辑和报文转发(尽管OpenFlow定义了多种Action,但是都可以归到这两类),例如添加一个vlan,修改IPDA,TTL减1,转发到某个端口或者某个group等。
动作列表(action list): 一个指令可能会指定对一个报文执行对个action,这里的多个action是在一个action list里面指定的。
除了流表相关的概念,OpenFlow转发面还有端口和组的概念:
端口(Port):在传统交换机里面,提到Port想到的就是物理端口。OpenFlow标准里面定义的三大类Port,物理端口(Physical Port)、逻辑端口(Logical Port)、保留端口(Reserved Port),物理端口就是交换机面板上所有对外可见的物理端口(带外管理口除外);逻辑端口的一个例子就是Tunnel,一个Tunnel就是一个逻辑端口;保留端口里面有很多种端口,具体可以参考OpenFlow标准,Controller Channel (连接Controller的通道,可以是带内业务口,也可以独立的带外管理口)就是一种保留端口。
组(Group): Group在OpenFlow标准里面被当作跟Flow Table并列的一个部件,但是这种划分不妥。Flow的Action之一就是将报文转发到一个Group, Group也分为好几种。OpenFlow里面说的Bucket就是指一个Action List, Bucket这个词仅用于Group里面。
all——转发到该group所包含的所有buckets,可以使用组播的方式实现
select——转发到该group所包含的所有buckets中的一个,可以使用等价路由ECMP或者端口聚合link aggregation。
indirect——在对个flow之间共享action,这种类型的group只包含一个buckets,当多个flow关联到同一个indirect类型的group时候,芯片里面就是多个flow entry指向同一个下一跳表项next hop entry。
fail-over——保护倒换,正常情况,报文只从这个group的一条路径发出去,一旦这条路径断了,备份路径马上顶上。
二、controller和交换机之间消息
controller和交换机之间的南向接口的消息,这些消息被controller用来控制交换机的转发行为以及被交换机用来通告状态给controller。这些消息是标准的,谁发起,谁接收,报文格式,参数列表等,都是标准的,不管是哪个厂商的controller连接哪个厂商的交换机,只要遵循标准,就可以互通。
消息分为三大类:controller-to-switch消息,asynchronous异步消息(也就是switch-to-controller消息),symmetric对称消息。
1.controller-to-switch
features——controller用这个消息类型询问交换机支持的功能
configuration——controller用这个消息类型去配置交换机或者查询交换机配置参数
modify-state——controller用这个消息类型来操作流表(add/delete/modify)和group表,以及port属性等
read-state——controller用这个消息类型来获取交换机各种状态信息。比如计数器
packet-out——controller用这个消息类型向外发送匹配某条流表的数据报文
barrier——controller用这个消息类型来保证一些其他消息之间的顺序。比如A和B两个消息有依赖关系,B依赖A,为了保证顺序,controller先给交换机发送消息A,然后再发送一个barrier消息,交换机要等消息A被执行之后发送一个对barrier消息的回复,controller收到回复之后,才会继续发送消息B
role-request——当交换机上连了多个controller时候,controller用这个消息类型向交换机通告自己的角色
asynchronous-configuration——当交换机上连了多个controller时候,会经常会主动朝controller发布一些状态通告消息或者转发报文,但是并非所有的controller对这些消息感兴趣,而这个消息类型就是被controller用来告诉交换机,对那些交换机发过来的消息感兴趣
2.asynchronous异步消息
packet-in——当有报文匹配某条流表项,该流表项的action是output to controller-port时候,这个报文会被通过packet-in的消息送到controller
flow-removed——当某个流表项被删除(老化或者controller主动要求删除),一个flow-removed的消息就会被送到controller来通告删除动作的完成
port-status——当端口状态发送变化的时候,交换机用这个消息类型向controller通告状态变化,比如link down/up
error——当交换机发送了一些错误的时候,用这个消息类型通知controller
3.symmetric对称消息
对称消息可以由任何一方发起;
hello——controller或者交换机启动的时候,互发hello消息
echo——通告发送echo以及得到reply,来确定与对方的连接没有问题,也可以用来测试延时
experimenter——让厂家进行私有扩展
三、OpenFlow channel
是指交换机与controller之间连接通道,可以是带外管理通道(交换机面板上跟console口在一起的那个单独的Ethernet端口,物理上跟业务端口分离),也可以是带内管理端口,常见的是带外管理端口,主要是简单,带内口得配置交换芯片和协议栈
OpenFlow channel连接是可以TCP连接的,也可以是加密的TLS连接,由设备商或者用户自己决定有那种。使用上述两个连接是为了保证可靠性,如果交换机连接多个controller连接,会创建多条TCP/TLS连接
四、controller角色和选举
一台OpenFlow交换机可以同时连接多个controller,这些controller之间是如何协作的,controller有三种角色,master,slave,equal
master——一台交换机连接的所有controller中,只能有一个master,它对交换机拥有完全的操作权限
slave——一台交换机连接的所有controller中,可以存在多个slave,对交换机只有读取状态和被动接收交换机消息的权限,不能对交换机进行配置,一旦master宕机,其中一台slave就被选举为master,每个slave可以接收不同类型的消息,从而在多个slave之间进行负载分担
equal——有的网络希望多个controller都能对交换机进行配置,以便进行负载分担,这种情况下controller被称为equal角色。
这些角色初始的时候是管理员配置的,当master故障时,slave可以通过选举成为master,交换机没有决定权,只有被通知权,OpenFlow标准并没有定义如何进行选举
五、OpenFlow系统性能指标
交换机处理带宽——芯片决定,无法优化
流表项数量——芯片决定,无法优化
流表项下发能力——每秒能安装多少流表项。这个指标与OpenFlow交换机收包/处理包能力,芯片SDN对流表项的处理能力,controller软件处理以及CPU主频有很大关系。通过提高CPU主频或者优化软件,是可以提高的。
to-controller报文转发——有些报文在交换机里面匹配到某条流表项时,动作是把报文送到controller,controller经过处理之后可能会再把报文通过交换机转发出去,这个转发的性能取决于controller和交换机两个元素
六、OpenFlow controller和交换机工作流程
1、系统初始化
交换机系统初始化的时候,一般都会有默认流表,默认流表里面有一条默认流表项。通常这条默认流表项的行为是丢弃所有报文或者将所有报文都送到Controller使便Controller进行处理,具体取决于厂商实现。
2、业务驱动controller增加/删除/修改表项
系统初始化完之后,根据具体业务需求, Controller开始往交换机下发流表项,或者修改已经存在的流表项的属性,或者删除不再需要的流表项。这些动作可以是管理员直接通过Controller 的命令行来操作(对于没有图形化操作界面的Controller ,或者通过图形化的应用程序界面来控制Controller去操作交换机流表,或者后台运行的应用程序自动去控制Controller操作流表。同时交换机也可以主动老化删除过期的流表项。
3、报文在交换机中转发
报文进到交换机之后,根据交换机配置去查找指定的流表,匹配到之后,就行相应的指令,这些指令包含的action最终会导致报文被编辑或者原封不动,被丢弃,被计数,被转发等。
七、对OpenFlow标准的总结
OpenFlow的标准就是match-action的过程,没有二三层的协议功能相关的描述,不知道什么是路由,不知道什么是网桥,唯一认识的就是查那种流表,匹配那些字段组合,执行什么动作。至于这些流表/字段/动作到底会组合出什么样的网络功能,不关心。
OpenFlow的本质:虽然不了解未来会有什么新的协议被发明,但是无论如何,现在设计的架构可以应对任何新的协议。