您好,欢迎来到意榕旅游网。
搜索
您的当前位置:首页openflow协议1.3.2中文版(1-7)

openflow协议1.3.2中文版(1-7)

来源:意榕旅游网
OpenFlow交换机规范(概要)

Version1.3.0(June25,2012)1介绍

本文档描述了对OpenFlow交换机的要求。此规范内容包括交换机的组件和基本功能,和一个远程控制器管理一个OpenFlow交换机的协议:OpenFlow。2交换机部件

OpenFlow的交换机包括一个或多个流表和一个组表,执行分组查找和转发,和到一个外部控制器OpenFlow的信道(图1)。该交换机与控制器进行通信,控制器通过OpenFlow协议来管理交换机。控制器使用OpenFlow协议,可以添加、更新和删除流流表中的表项,主动或者被动响应数据包。在交换机中的每个流表中包含的一组流表项;每个流表项包含匹配字段,计数器和一组指令,用来匹配数据包(见5.2)。匹配从第一个流表开始,并可能会继续匹配其它流表(见5.1)。流表项匹配数据包是按照优先级的顺序,从每个表的第一个匹配项开始(见5.3)。如果找到一个匹配项,那么与流表项相关的指令就会去执行。如果在流表中未找到匹配项,结果取决于漏表的流表项配置:(例如,数据包可能通过OpenFlow信道被转发到控制器、丢弃、或者可以继续到下一个的流表,见5.4)。与流表项相关联的指令包含行动或修改流水线处理(见5.9)。行动指令描述了数据包转发,数据包的修改和组表处理。流水线处理指令允许数据包被发送到后面的表进行进一步的处理,并允许信息以元数据的形式在表之间进行通信。当与一个匹配的流表项相关联的指令集没有指向下一个表的时候,表流水线停止处理,这时该数据包通常会被修改和转发(见5.10)。流表项可能把数据包转发到某个端口。这通常是一个物理端口,但它也可能是由交换机定义的一个逻辑端口或通过本规范中定义的一个保留的端口(见4.1)。保留端口可以指定通用的转发行为,如发送到控制器、泛洪、或使用非OpenFlow的方法转发,如“普通”交换机转发处理(见4.5);而交换机定义的逻辑端口,可以是指定的链路汇聚组、隧道或环回接口(见4.4)。与流表项相关的行动,也可直接把数据包发送到组,进行额外的处理(见5.6)。组表示一组泛洪的指令集,以及更复杂的转发(如多路径,快速重路由,链路聚合)。作为间接的通用层,组也使多个流表项转发到同一个标识者(例如IP转发到一个共同的下一跳)。这种抽象的行为使相同的输出行动非常有效。组表包含若干组表项,每个组表项包含一系列依赖于组类型的特定含义行动存储段(见5.6.1)。一个或多个行动存储段里的行动会作用到发送到该组的数据包。只要正确的匹配和指令含义保持不变,交换机设计者可以任意的实现内部结构。例如,当一个流表项使用一个所有组来转发至多个端口,交换机设计人员可以在硬件转发表中用一个单一的位掩码去实现。另一个例子是匹配;如果OpenFlow交换机是通过不同数量的硬件表进行物理实现的,那么流水线就会被暴露。3名词解释

本节介绍了关键的OpenFlow规范术语:.字节:一个8位位组。.数据包:以太网帧,包括报头和有效载荷。.端口:数据包进入和退出OpenFlow的流水线地方(见4.1)。可以是一个物理端口,由交换机定义的一个逻辑端口,或由OpenFlow的协议定义的一个保留端口。.流水线:在一个openflow交换机中提供匹配、转发和数据包修改功能的相连流表的集合。.流表:流水线的一个阶段,包含若干流表项。.流表项:在流表中用于匹配和处理数据包的一个元素。它包含用于匹配数据包的匹配字段、匹配次序的优先级,跟踪数据包的计数器,以及应用的指令集。.匹配字段:用来匹配数据包的字段,包括包头,进入端口,元数据值。一个匹配字段可能会进行通配符匹配(匹配任何值)或者在某些情况下通过位掩码进行匹配。.元数据:一个可屏蔽寄存器的值,用于携带信息从一个表到下一个表。.指令:指令存在于流表项中,当数据包匹配流表项时,指令用来描述OpenFlow的处理方式。指令要么改变流水线处理,如指导包匹配另一个流表,要么包含一组添加到行动集的行动,或包含一组立即应用到数据包的行动。.行动:是一种操作,可将数据包转发到一个端口或修改数据包,如TTL字段减1。行动可以是与流表项相关联的指令集的一部分,或者是与组表项相关联的行动存储段的一部分。我们可以将行动积累在数据包的行动集里,也可以立即将行动应用到该数据包。行动集:与数据包相关的行动集合,在数据包被每个表处理的时候这些行动可以累加,在指令集指导数据包退出处理流水线的时候这些行动会被执行。.组:一系列的行动存储段和选择一个或者多个存储段应用到每个数据包的手段。.行动存储段:行动和相关参数的集合,为组而定义的。.标记:一个头部,可以通过压入行动插入到数据包或者通过弹出行动进行移除。.最外层的标记:一个数据包最开始出现的标记。.控制器:与OpenFlow交换机使用OpenFlow协议交互的实体。.计量:一个交换机元件,可以测量和控制数据包的速度。当通过计量的数据包速率或字节速率超过预定义的阈值时,计量触发计量带。如果计量带丢弃该数据包,它则被称为一个限速器。4OpenFlow端口

本节介绍了OpenFlow的端口的概念和OpenFlow支持的各类端口。4.1OpenFlow端口OpenFlow的端口是OpenFlow处理机和网络其余部分之间传递数据包的网络接口。OpenFlow交换机之间通过OpenFlow端口在逻辑上相互连接。OpenFlow交换机提供一定数量的OpenFlow端口,开放给OpenFlow的处理机。OpenFlow的端口组可能与交换机硬件中提供的网络端口组不完全相同,因为有些硬件网络接口可能被OpenFlow禁用,OpenFlow交换机可能定义额外的端口。OpenFlow的数据包从入端口接收,经过OpenFlow的流水线处理(见5.1),可将它们转发到一个输出端口。入端口是数据包的属性,它贯穿整个OpenFlow流水线,并代表数据包是从哪个OpenFlow交换机的端口上接收的。匹配数据包的时候会用到入端口(见5.3)。OpenFlow流水线可以决定数据包通过输出行动发送到输出端口(见5.12),还定义了数据包怎样传回到网络中。一个OpenFlow交换机必须支持三种类型的OpenFlow的端口:物理端口,逻辑端口和保留端口。4.2标准端口OpenFlow的标准端口为物理端口,逻辑端口,本地保留端口(其他保留的端口除外)。标准端口可以被用作入口和出端口,它们可在组里使用(见5.6),都有端口计数器(见5.8)。4.3物理端口OpenFlow的物理端口为交换机定义的端口,对应于一个交换机的硬件接口。例如,以太网交换机上的物理端口与以太网接口一一对应。在有些应用中,OpenFlow交换机可以实现交换机的硬件虚拟化。在这些情况下,一个OpenFlow物理端口可以代表一个与交换机硬件接口对应的虚拟切片。4.4逻辑端口OpenFlow的逻辑端口为交换机定义的端口,并不直接对应一个交换机的硬件接口。逻辑端口是更高层次的抽象概念,可以是交换机中非OpenFlow方式的端口(如链路汇聚组,隧道,环回接口)。逻辑端口可能包括数据包封装,可以映射到不同的物理端口。这些逻辑端口的处理动作相对于openflow处理机来说必须是透明的,而且这些端口必须像硬件端口一样与openflow处理机互通。物理端口和逻辑端口之间的唯一区别是:一个逻辑端口的数据包可能有一个叫做隧道ID的额外的元数据字段与它相关联(见7.2.3.7);而当一个逻辑端口上接收到的分组被发送到控制器时,其逻辑端口和底层的物理端口都要报告给控制器(见7.4.1)。4.5保留端口OpenFlow的保留端口由本规范定义。它们指定通用的转发动作,如发送到控制器,泛洪,或使用非OpenFlow的方法转发,如“正常”交换机处理。一个交换机不需支持所有的保留端口,只支持那些标记为“Required”的保留端口。.Required:ALL:表示交换机可转发指定数据包到所有端口,它仅可用作输出端口。在这种情况下,数据包被复制后发送到所有的标准端口,不包括数据包的入端口和端口被配置为OFPPC_NO_FWD。.Required:CONTROLLER:表示OpenFlow控制器的控制通道,它可以用作一个入端口或作为一个出端口。当用作一个出端口,数据包封装进输入包消息,并使用OpenFlow协议发送(见7.4.1)。当用作一个入口端口,确认数据包来自控制器。.Required:TABLE:表示openflow流水线的开始(见5.1)。这个端口仅在输出包消息的行动列表里的输出行为时候有效(见7.3.7),此时交换机提交报文给第一流表使数据包可以通过OpenFlow流水线处理。.Required:INPORT:代表数据包的进入端口。当数据包通过它的入端口发送出去的话,只能用作输出端口。.Required:ANY:特别值,用在未指定端口的OpenFlow命令(端口通配符)。既不能作为入口端口,也不能作为一个输出端口。.Optional:LOCAL:表示交换机的本地网络堆栈和管理堆栈。可以用作一个入口端口或作为一个输出端口。远程实体通过本地端口与交换机和网络服务互通,而不是通过一个的控制网络。利用一组合适的默认流表项,本地端口被用来实现一个带内控制器连接。.Optional:NORMAL:代表传统的非OpenFlow流水线(见5.1)。仅可用于为一个输出端口,使用普通的流水线处理数据包。如果交换机不能转发数据包从OpenFlow流水线到普通流水线,它必须表明它不支持这一行动。.Optional:FLOOD:表示使用普通流水线处理进行泛洪(见5.1)。只作为一个输出端口,一般可以将数据包发往所有标准端口,但不能发往入端口或OFPPS_BLOCKED状态的端口。交换机也可以通过数据包的VLANID选择哪些端口泛洪。OpenFlow-only交换机不支持NORMAL端口和FLOOD端口,而OpenFlow-hybrid交换机均支持上述端口(见5.1)。转发数据包到FLOOD端口依赖交换机的实现和配置,若使用一组all类型进行转发,则可以使控制器能更灵活地实现泛洪(见5.6.1)。5OpenFlow表

本节描述流表和组表的组件,以及匹配和行动处理的机制。5.1流水线处理OpenFlow兼容的交换机有两种类型:OpenFlow-only和OpenFlow-hybrid。OpenFlow-only交换机只支持OpenFlow操作,在这些交换机中的所有数据包都由OpenFlow流水线处理,否则不能被处理。OpenFlow-hybrid交换机支持OpenFlow的操作和普通的以太网交换操作,即传统的L2以太网交换、VLAN隔离、L3路由(IPv4的路由,IPv6路由)、ACL和QoS处理。这种交换机必须提供一个OpenFlow外的分类机制,使流量路由到OpenFlow流水线或普通流水线。例如,某个交换机可以使用VLAN标记或数据包的输入端口,来决定是否使用一个流水线或其它流水线,或者它可引导所有数据包都到OpenFlow流水线进行处理。这种分类机制超出了本规范的范围。一个OpenFlow-hybrid交换机也允许数据包通过NORMAL和FLOOD保留端口从OpenFlow流水线转移到普通流水线处理(见4.5)。每个OpenFlow交换机的流水线包含多个流表,每个流表包含多个流表项。OpenFlow的流水线处理定义了数据包如何与那些流表进行交互(参见图2)。OpenFlow交换机至少需要一个流表,可选更多的流表。只有单一流表的OpenFlow交换机是有效的,而且在这种情况下流水线处理进程可以大大简化。Figure2:通过流水线处理的数据包流OpenFlow交换机的流表按顺序编号的,从0开始。流水线处理总是从第一流表开始:数据包首先与流表0的流表项匹配。其他流表根据第一个表的匹配结果来调用。被一个流表处理时,数据包与流表中的流表项进行匹配,从而选择一个流表项(见5.3)。如果匹配了流表项,则执行在该流表项里的指令;这些指令可能明确指导数据包传递到另一个流表(使用Goto指令,见5.9),在那里同样的处理被重复执行。一个流表项只能指导数据包到大于自己表号的流表,换句话说流水线处理,只能前进而不能后退。显然,流水线的最后一个表项可以不包括GOTO指令。如果匹配的流表项并没有指导数据包到另一个流表,流水线处理将停止在该表中。当流水线处理停止,数据包被与之相关的行动集处理,通常是被转发(见5.10)。如果数据包在流表中没有匹配到流表项,这是一个漏表行为。漏表行为取决于表的配置(见5.4)。一个流表中的漏表项可以指定如何处理无法匹配的数据包:可以选择丢弃,传递到另一个表,或利用输入包消息通过控制信道发送到控制器去(见6.1.2)。Openflow流水线和各种Openflow操作用同样的方法处理特定类型的数据包和规范定义的相同类型的包,除非目前的规范或Openflow配置规定了不同的方法。例如,Openflow定义的以太头部必须与IEEE规范一致,Openflow使用的TCP/IP头部定义必须与RFC规范一致。另外,Openflow交换机的包重排序必须与IEEE规范的要求一致,保证数据包能被流表项、组表和计量带同样的处理。5.2流表

一个流表中包含多个流表项。每个流表项包含:.匹配字段:对数据包匹配。包括入端口和数据包头,以及由前一个表指定的可选的元数据。.优先级:流表项的匹配次序。.计数器:数据包匹配时更新计数。.指令:修改行动集或流水线处理。.超时:最大时间计数值或流在交换机中失效之前的剩余时间。.cookie:由控制器选择的不透明数据值。控制器用来过滤流统计数据、流修改和流删除。但处理数据包时不能使用。流表项通过匹配字段和优先级决定:在一个流表中匹配字段和优先级共同确定唯一的流表项。所有字段通配(所有字段省略)和优先级等于0的流表项被称为table-miss流表项(见5.4)。5.3匹配Figure3:流程图详细描述了数据包流通过一个OpenFlow交换机。当OpenFlow交换机接收一个数据包,就执行图3所示的功能。交换机开始对第一个流表进行查找,并基于流水线处理,也可能在其它流表中(见5.1)执行表查找。数据包匹配字段是从数据包中提取的。用于表查找的数据包匹配字段依赖于数据包类型,也就是包括各种数据包头部字段,如以太网源地址或IPv4目的地址(见7.2.3)。除了通过数据包报头中进行匹配,也可以通过入端口和元数据字段进行匹配。元数据可以用来在一个交换机的不同表里面传递信息。数据包匹配字段表示数据包的当前状态,如果在前一个表中使用Apply-Actions改变了数据包的报头,那么这些变化也会在数据包匹配字段中反映。如果数据包中用于查找的匹配字段值匹配了流表项定义的字段,就表示这个数据包匹配了此流表项。如果流表项字段的值是ANY(字段省略),它就可以匹配包头部的所有可能的值。如果交换机支持对指定的匹配字段进行任意的的位掩码,这些掩码可以更精确地进行匹配。数据包与表进行匹配,而且只有匹配数据包的最高优先级的表项必须被选择,此时与所选流表项相关的计数器也会被更新,所选流表项的指令集也会被执行。如果多个匹配的流表项具有相同的最高优先级,所选流表项则被确定为未定义表项。只有控制器记录器在流信息中没有设置OFPFF_CHECK_OVERLAP位并且增加了重复的表项的时候,这种情况才能出现。如果交换机配置中包含OFPC_FRAG_REASM标志(见7.3.2),则在流水线处理前IP碎片必须被重新组装。当交换机接收到一个格式不正确或损坏的数据包,此版本的规范没有定义预期的行为。5.4Table-miss

每一个流表必须支持table-miss的流表项来处理漏表。table-miss表项指定如何处理在流表中与其他流表项未匹配的数据包(见5.1),比如把数据包发送给控制器、丢弃数据包或直接将包扔到后续的表。table-miss流表项也有它的匹配字段和优先级(见5.2),它通配所有匹配字段(所有字段省略),并具有最低的优先级(0)。table-miss流表项的匹配可能不属于正常范围内流表支持的匹配,例如精确匹配表可能不支持在其他流表项中使用通配符,但必须支持table-miss流表项通配所有字段。table-miss流表项可能不具备正常流表项(见7.3.5.5)相同的能力。table-miss流表项必须至少支持利用CONTROLLER保留端口将数据包发送到控制器(见4.5),和使用Clear-Actions指令(见5.9)丢弃数据包。为了和早期版本规范一致,如果可能,在实现中鼓励支持引导包给后续的表。table-miss表项的行为在许多方面像任何其他流表项:默认情况下,在流表中不存在table-miss表项。控制器可以在任何时候添加或删除它(见6.4),而且它可能会超时失效(见5.5)。table-miss流表项像期望的那样,利用它的匹配字段和优先级匹配表中的数据包。table-miss流表项可以匹配流表中其他表项中不能匹配的数据。当数据包与table-miss表项匹配时,table-miss表项指令就会执行(见5.9)。如果该table-miss表项直接将数据包通过CONTROLLER保留端口发送到控制器(见4.5),那么数据包输入的原因必须标识出table-miss表项(见7.4.1)。如果该table-miss表项不存在,默认情况下,流表项无法匹配的数据包将被放弃(丢弃)。交换机配置时,例如使用OpenFlow配置协议,可以覆盖此默认值,指定其他行为。5.5流表项删除

流表项可以通过两种方式在流表中删除,一个是通过控制器的请求,一个是利用交换机的流超时机制。交换机的流超时机制于控制器,由交换机根据流表项的状态和配置来运行。每个流的表项具有一个和它相关的idle_timeout和hard_timeout值。如果hard_timeout值不为零,交换机必须注意的流表项的老化时间,因为交换机可能删除该项。一个非零hard_timeout字段可能在规定数秒后引起流表项被删除,无论有多少数据包与之匹配。如果给定非零idle_timeout的值,交换机必须注意与流的最后一个数据包到达的时间,可能后面需要删除这个流表项。当在规定数秒内没有匹配数据包时,一个非零idle_timeout字段将引起流表项删除。交换机必须实现流表项超时就会从流表中删除的功能。控制器可以主动发送DELETE流表修改消息(OFPFC_DELETE,或OFPFC_DELETE_STRICT-见6.4),从流表中删除流表项。流表项被删除时,不管是控制器或流表项超时引起的,交换机必须检查流表项的OFPFF_SEND_FLOW_REM标志。如果该标志被设置,该交换机必须将流删除消息发送到控制器。每个流删除消息中包含一个完整的流表项描述、清除的原因(超时或删除),在清除时的流表项的持续时间,在清除时的流的统计数据。5.6组表

一个组表包括若干组表项。一个流表项指向一个组的能力使得openflow可以实现额外的转发方法(例如选择部分和所有)。每个组表项(见表2)由组编号确定,具体内容包含:.组编号:一个32位的无符号整数,唯一标识该组.组类型:确定组语义(参见5.6.1节).计数器:当数据包被组处理时更新.行动存储段:有序的行动存储段,其中的每个行动存储段包含了一组要执行的行动和相关参数。5.6.1组类型交换机只支持那些标记为“Required”的组类型,控制器可以查询交换机支持哪些“Optional”组类型。.Required:all:执行组中的所有存储段。这个组用于多播或广播的转发。数据包为每个存储段都有效地复制一份,然后被每个存储段处理。如果某个存储段中明确地指导数据包发往入端口,那么这个复制的包被丢弃。如果控制器记录器希望数据包从入端口转发出去,那么这个组必须包含一个额外的存储段,这个存储段包含到OFPP_IN_PORT保留端口的输出行动。.Optional:select:执行组中的一个存储段。基于交换机计算选择算法(如利用用户配置的元组/数组的哈希算法或简单的循环算法),数据包被组中的一个存储段处理。选择算法的所有配置和状态都在OpenFlow外部运行。选择算法实现可以使用等负荷分配,也可以选择根据存储段权重进行。当组中存储段所指定的端口出现故障时,交换机可对剩余部分(具有转发到有效端口行为的)选择存储段,而不是丢弃数据包。此行为可能会减少数据包在链路或交换机的中断。.Required:indirect:执行此组中定义的一个存储段。这个组只支持单一的存储段。允许多个流表项或者组指向一个共同的组编号,这样可以使转发更快,更高效的汇聚(例如:下一跳IP转发)。对于只有一个存储段的所有组,组类型应该是相同的。.Optional:fastfailover:执行第一个有效的存储段。每一个行动存储段与控制其有效性的一个指定端口/或组相关。组定义的存储段是有序的,首选选择与有效的端口或者组相关的第一个存储段。这个组类型可以使交换机改变转发,而无需通知控制器。如果没有有效的存储段,数据包将被丢弃。组类型必须实行有效机制(见6.5)。5.7计量表

一个计量表包含若干计量表项,确定每个流的计数。每个流的计数可以使OpenFlow实现各种简单的QoS操作,如限速,并且可以结合每个端口队列(见5.12)来实现复杂的QoS构架,如DiffServ。计量器可以测试数据包分配的速率,并可以控制数据包的速率。计量器直接连接到流表项(而不是被连接到端口的队列)。任意的流表项可以在它的指令集中定义一个计量器(见5.9),计量器测量和控制和它有关的所有流表项的总速率。在同一个表中可以使用多个计量器,但必须使用专用的方式(流表项分离设置)。在连续的流表中,对于同样的数据包集合,可以使用多个计量器。每个计量表项(见表3)由其计量标识符来区分,其包含:.计量器的标识符:一个32位的无符号整数唯一识别.计量带:计量带的无序列表,其中每个计量带指定带速和处理数据包的方式.计数器:计量器处理数据包时进行更新计数。5.7.1计量带每个计量器可能有一个或多个计量带。每个带指定所用的速率和数据包处理的方式。单个计量带以当前测量的计量速率处理数据包。当测量速率超过最高配置速率的时候,计量器就启用计量带。若当前的速率比任何指定的计量带速率率低,就没有计量带需要工作。每个计量带(见表4)用速率来识别,包括:.带类型:定义了数据包如何处理.速率:用于计量器选择计量带,也就是计量带可以启用的最低速率.计数器:当计量带处理数据包时更新计数.类型的特定参数:带类型的可选参数在本规范里带类型没有“Required”。控制器可以查询交换机支持的计量带类型“Optional”.Optional:drop:丢弃数据包。可以用来定义速率带。.Optional:dscpremark:增加数据包的IP头部DSCP字段丢弃的优先级。可用于定义一个简单的DiffServ策略。5.8计数器

每一个流表,流表项,端口,队列,组,组存储段,计量器和计量带都会修改计数器。OpenFlow-compliant计数器可以在软件中实现,也可以通过查询硬件计数器获取计数进行有限范围的修改。表5中包含了openflow规范中定义的计数器集。交换机不要求支持所有的计数器,只有那些标记为“Required”是必须支持的。持续时间指的是流表项,端口,组,队列或计量器在交换机中已安装的时间数值,而且必须精确到秒。ReceivedErrors字段是表5里定义的所有收到的和冲突的错误总和,也包括表里未列出的其它错误。计数器都是无符号值,可以环回且没有溢出指示。如果交换机里没有指定值的计数器,则其值必须设置成字段的最大值(无符号数就是-1)。5.9指令

每个流表项中包含一组指令集,当一个数据包匹配表项时指令就会被执行。这些指令可导致数据包,行动组和/或流水线处理发生改变。交换机不需要支持所有类型的指令,只需支持下面那些标记为“RequiredInstruction”。控制器可查询交换机支持的“OptionalInstruction”。.OptionalInstruction:Metermeter_id:将包转给指定的计量器。计量的结果可能会丢弃这个数据包(依赖于计量器的配置和状态)。.OptionalInstruction:Apply-Actionsaction(s):立即执行指定的行动,而不改变行动集。在两个表之间传递或者执行同类型的多个行动的时候,这个指令可用来修改数据包。这些行动被指定为一个行动列表(见5.11)。.OptionalInstruction:Clear-Actions:立即清除行动集中的所有行动。.RequiredInstruction:Write-Actionsaction(s):将指定的行动添加到当前的行动集中。如果行动存在于当前集合中,则进行覆盖,否则进行追加。.OptionalInstruction:Write-Metadatametadata/mask:在元数据字段写入掩码的元数据数值。掩码指的是元数据寄存器应进行修改的比特。(new_metadata=old_metadata&~mask|value&mask)。.RequiredInstruction:Goto-Tablenext-table-id:指示流水线处理的下一张表。表ID必须大于当前表ID。流水线最后一张表的流表项不能含有这个指令(见5.1)。Openflow交换机若只有一个流表则不需要实现这个指令。流表项所属的指令集中每个类型的单个指令都有个最大值。指令就是按照上述列表中指定的顺序来执行。实际上,有限定的是:Meter指令在Apply_Actions指令前执行,Clear_Actions指令在Write_Actions指令前执行,Goto_Table最后执行。如果流表项不能执行相关指令,交换机必须拒绝这个流表项。这种情况,交换机必须返回一个不支持的流错误信息(见6.4)。流表不一定支持每个匹配,每个指令或每个行动。5.10行动集

行动集是与每个数据包相关的,默认情况下是空的。一个流表项可以使用Write-Action指令或者与特殊匹配有关的Clear-Action指令来修改行动集。行动集在表间被传递。当一个流表项的指令集没有包含Goto-Table指令时,流水线处理就停止了,然后数据包的行动集执行其行动。行动集中每个类型的行动有一个最大值。set_field行动用字段类型来标识,因此行动集对每个字段类型的set_field行动(即,多个字段可被设置)有个最大值。当同一个类型需要多个行动时,例如,压入多个MPLS标签或弹出多个MPLS标签,应使用Apply_Actions指令(见5.11)。行动集中所有的行动,不管它们以什么顺序添加到行动集中,行动的顺序均按照下列顺序执行。如果行动集包含组行动,那么组行动存储段中的行动也按照下列顺序执行。当然,交换机也可以支持通过Apply-Actions指令任意修改行动执行顺序。1.copyTTLinwards:向数据包内复制TTL的行动2.pop:从数据包弹出所有标记的行动3.push-MPLS:向数据包压入MPLS标记的行动4.push-PBB:向数据包压入PBB标记的行动5.push-VLAN:向数据包压入VLAN标记的行动6.copyTTLoutwards:向数据包外复制TTL的行动7.decrementTTL:将数据包的TTL字段减18.set:数据包使用所有的set_field行动9.qos:使用所有的QOS行动,如对数据包排队10.group:如果指定了组行动,那么按顺序执行组行动存储段里的行动。11.output:如果没有指定组行动,数据包就会按照output行动中指定的端口转发。行动集中的Output行动是最后执行的。如果在一个行动集里组行动和输出行动都存在,则组行动优先。如果两者均不存在,数据包将被丢弃。如果交换机支持的话,组的执行将返回;组存储段可指定另外一个组,在这种情况下,行动将在组配置中指定的所有组中执行。5.11行动列表Apply-Actions指令和Packet-out消息包含一个行动列表。行动列表的含义与Openflow1.0规范的相同。行动列表中的行动按照列表中的次序执行,并立即作用到数据包。列表中的行动从第一个行动开始执行,行动都是按序执行的。行动的结果是累积的,比如行动列表中有两个pushVLAN行动,数据包就会被加上两个VLAN头部。如果行动列表有一个输出行动,一个当前状态下的包复制后就转发给所需端口。如果列表包含组行动,相关组存储段就会处理当前状态下的复制包。一个Apply_Actions指令执行完一个行动列表后,流水线继续处理已修改的数据包(见5.1)。数据包的行动集本身在行动列表执行的时候没有改变。5.12行动

交换机不要求支持所有类型的行动,只需支持标记为“RequiredAction”。控制器也可查询交换机所支持的“OptionalAction”。RequiredAction:Output.数据包输出到指定Openflow端口(见4.1)。Openflow交换机必须支持转发到物理端口,交换机定义的逻辑端口和所需的保留端口(见4.5)。OptionalAction:Set-Queue.设置数据包的队列ID。当数据包使用输出行动转发到一个端口,队列ID决定数据包安排到端口所属的哪个队列并转发。转发行为受队列配置控制,并用来提供Qos支持(见7.2.2)。RequiredAction:Drop.没有明确的行动来表现丢弃。相反,那些行动集中没有输出行动的数据包应该被丢弃。当流水线处理时或执行Clear_Actions指令后,空指令集或空指令行动存储段会导致丢弃这个结果。RequiredAction:Group.通过指定的组处理数据包,准确的解释依靠组类型。OptionalAction:Push-Tag/Pop-Tag.交换机可具有压入/弹出表6所示标记的能力。为了和已有网络更好结合,建议支持压入/弹出VLAN标记的能力。最新的压入标记应插入到最外侧有效位置作为最外侧的标记。当压入一个新VLAN标记,应作为最外侧标记来插入,位于以太头部后面,其它标记前面。同样的,当压入一个新MPLS标记,也应作为最外侧标记来插入,位于以太头部后面,其它标记前面。当多个压入行动添加到数据包行动集,按照行动集定义的规则依次作用到数据包,开始时MPLS,接着是PBB,后面是VLAN(见5.10)。当一个行动列表中有多个压入行动,按照列表次序(见5.11)作用到数据包。注意:5.12节所涉及的信息都是默认字段值。OptionalAction:Set-Field.不同Set-Field行动由它们的字段类型来标识,并对数据包中头部字段分别修改数值。当要求不很严格时,若支持使用Set-Field行动进行重写头部各字段将非常有益于Openflow的实现。为了和已有网络更好结合,建议支持VLAN修改行动。Set-Field行动应一直作用到头部可能的最外侧(例如,“setVLANID”行动一直设置VLAN标记的最外侧ID),除非该字段类型指定其它值。OptionalAction:Change-TTL.不同Change-TTL行动修改数据包中的IPV4TTL、IPV6HopLimit或MPLSTTL。当要求不很严格时,表7所示的行动非常有益于Openflow中路由功能的实现。Openflow交换机检查出携带无效IPTTL或MPLSTTL的数据包并拒绝接收。不是每个数据包都需要检查TTL是否有效,但是每次数据包完成TTL减1行动后应在最短时间内检查。交换机可能会改变其异步配置(见6.1.1)),利用输入包消息通过控制信道发送携带无效TTL的数据包给控制器(见6.1.2)。5.12.1字段压入的默认值当执行压入行动时,表8中所有字段指定的值应从已有外部头复制给新建外部头。表8中所列的新字段与已有字段不一致的应设置为0。Openflowset_field行动不能修改的字段用初始化成合适的协议数值。在压入操作之后,可通过指定的“set”行动对新建头部的某些字段进行设置。6、openflow通道

Openflow通道是每个交换机连接控制器的接口,通过这个接口,控制器配置和管理交换机,接收来自交换机的事件,将包从交换机转发出去。尽管所有openflow通道消息必须遵守openflow协议格式,但在数据通路和openflow通道之间,接口是具体实施者。openflow通道通常使用TLS加密,但也可能直接在TCP上运行。6.1openflow协议概述

Openflow协议支持三种消息:控制器到交换机消息、异步消息和对称消息,每个都有多个子消息类型。controller-to-switch消息由控制器发起,用来直接管理检查交换机的状态;异步消息由交换机发起,用于控制器更新网络事件和交换机状态变化;对称消息由交换机或者控制器发起,而且无需请求。下面介绍Openflow使用的消息类型。6.1.1Controller-to-SwitchController-to-Switch是由控制器发起,不强求交换机作出回应。Features:控制器通过发送feature请求查询交换机的身份以及基本功能,交换机必须响应,回答其身份和基本能力。通常在openflow通道建立后运行。Configuration:控制器用来设置、查询交换机的配置参数。交换机仅需要回应来自控制器的查询消息。Modify-State:mmodify-sate消息由控制器发出,用来管理交换机的状态。它们的首要目标是增加、删除、修改openflow表中的流表项/组表项,以及设置交换机的端口属性。Read-state:控制器用Read-state消息收集交换机的各种消息,例如当前配置、统计数据和性能等。Packet-out:控制器用这个Packet-out发送数据包到交换机特定的端口。并且转发通过Packet-in消息收到的数据包。Packet-out消息必须包括一个完整的数据包或者一个指明交换机中存储数据包缓冲区的ID。这个消息必须包含一个动作列表,并按指定顺序应用这些动作。若动作列表为空则丢弃该包。Barrier:控制器使用Barrier请求/回复消息确保消息依赖已经遇到或者收到操作完成的通知。Role-Request:控制器使用Role-Request消息,用来设置openflow通道角色,或者查询这个角色。当交换机连接多个控制器时这个消息则非常有用(见6.3.4)。Asynchronous-Configuration:控制器使用Asynchronous-Configuration消息来设置一个附加过滤器,滤出想在openflow通道中接受的异步消息,或者用来查询这些过滤器。这个消息在交换机连接多个控制器时非常有用(见6.3.4),通常在openflow通道建立后运行。6.1.2Asynchronous交换机发送Asynchronous消息时无需控制器的请求,通知控制器数据包到达、交换机状态改变或错误。四个主要的异步消息描述如下。Packet-in:将对包的控制转移给控制器。由于全部数据包使用流表项或者漏表项转发到“CONTROLLER”保留端口,一个packet-in事件就会发给控制器(见5.12)。其他处理,例如TTL检查,也可能产生packet-in事件将数据包发给控制器。缓冲数据包可以配置packet-in事件。由流表项或者组存储段中的输出行动产生的packet-in,可以在输出行动中各自分别指定(见7.2.5),其他的packet-in可在交换机中配置(见7.3.2)。如果这个packet-in事件配置给缓冲数据包,并且交换机中有足够的缓存,在交换机准备转发这个数据包时,这个packet-in事件仅仅包含数据包头部的一部分和控制器使用的缓冲ID。不支持内部缓冲的交换机,packet-in事件配置为不缓冲数据包,或内部缓冲耗尽时,将整个包作为事件的一部分发送给控制器。缓冲的数据包通常是利用控制器发来的packet-out消息进行处理,或者一段时间后自动过期。如果数据包已缓冲,包含在packet-in中的原始包字节数就可以配置,默认的是128字节。由流表项或者组存储段中的输出行动产生的packet-in,可以在输出行动中各自分别指定(见7.2.5),其他的可在交换机中配置(见7.3.2)。(注:交换机缓存足够,包被临时放在缓存中,包的部分内容(默认128字节)和在交换机缓存中的序号也一同发给控制器;如果交换机缓存不足以存储包,则将整个包作为消息的附带内容发给控制器)Flow-Removed:通知控制器一个流表项从流表中移除。流表项只有设置了OFPFF_SEND_FLOW_REM标志,Flow-Removed消息才会发送。此消息是由于控制器的流删除请求产生,或者交换机流处理超时产生,即某个流有效时间超出范围了。Port-status:通知控制器某个端口发生变化。交换机需要在端口配置或状态改变时发送port-status消息给控制器。包括端口配置的改变等事件,例如,端口被用户关闭,端口状态被用户改变,连接断开等。Error:交换机用Error消息通知控制器出现问题。6.1.3Symmetric(对称)Symmetric(对称)消息向每个方向发送时无需询问。包括Hello,Echo,Experimenter三种消息。Hello:Hello消息在连接一旦建立,就在交换机和控制器之间传递。Echo:从交换机或者控制器发出的Echo应答/请求消息,必须得到一个返回的Echo响应消息。他们主要用来验证controller-switch连接是否活跃,也可能来测量延迟率和带宽。Experimenter:Experimenter消息为交换机在其消息类型中提供附加功能提供了一个标准的方法。这是将来openflow修订时的一个功能中转区。6.2MessageHanding(消息处理)

Openflow协议提供可靠的消息传递和处理,但是不自动提供确认和保证消息的有序化处理。这一节所说的openflow消息处理行为是由可靠传输的主辅链接上完成的。MessageDelivery:消息可靠传输,除非Openflow通道完全失败,控制器不了解交换机的任何状态(如交换机可能已经进入了“失败模式”)。MessageProcessing:交换机必须完全处理从控制器接收的每个消息,并可能生成一个回复。如果交换机不能完全处理来自控制器的消息,那么它必须返回一个error消息。对于pack-out消息,消息被完全处理之后也不能保证包实际上退出了交换机。由于交换机的堵塞、QoS策略、或者数据包发送到一个阻塞或无效的端口,交换机处理之后数据包可能被丢弃。此外,交换机须发送所有OpenFlow状态改变时产生的异步消息,例如流删除,端口状态或者packet-in消息,这样控制器就可以与交换机的实际情况同步。基于异步配置(见6.1.1),这些消息可能被过滤,而且,在引起这些变化之前,触发Openflow状态改变的环境可能会被过滤掉。例如,数据端口接收的用来发送到控制器的数据包,由于交换机的阻塞或QoS策略和packet-in消息的缺失,可能被丢弃。这些丢失在数据包对控制器有明显的输出行动时会发生,也可能在数据包在表项里匹配失败产生,尽管表的默认行动是发给控制器。(这个错误会被发送到交换机)。发给控制器的数据包建议采用QoS行动和速率进行监管,以防止控制器链接的拒绝服务,此内容超出本规范范围。控制器可以自由忽略他们接收的消息,但是必须响应应答消息来防止交换机中断连接。MessageOrdering:排序可以通过使用barrier消息来保证。在缺少屏障消息时,交换机可以任意重新排序消息,来达到最佳性能。因此,交换机不应该依赖一个特定的处理顺序。特别的是,流表项插入到流表时,其顺序不同于交换机接收到的流模式。消息跨越一个屏障消息就不需要重新排序,只有前面所有的消息都处理后屏障消息才被处理。具体的说:1.屏障消息前面的消息必须先被处理,包括发送任何产生的错误和回复。2.屏障必须被处理,而后发送一个响应。3.屏障消息后面的消息可继续处理。如果从控制器接收到的2个消息是相互依赖的,那他们必须通过屏蔽消息来分离。6.3Openflow通道连接Openflow通道用来在控制器和交换机之间交换Openflow消息。控制器管理多个Openflow通道,每个通道连接到一个不同的交换机。一个交换机可能有一个通道连到控制器,或者,有多个通道连接到不同的控制器(见6.3.4)。控制器可以通过一个或者多个网络来远程管理交换机。这种方法是不在当前规范之内的,所使用的可能是一个的专用网络,或者由交换机管理的网络(带内控制器连接)。唯一的要求就是应提供TCP/IP连接。Openflow通道实际上作为一个交换机和控制器之间的单一的网络连接,使用TLS或TCP协议(见6.3.3)。另外,为了具有并行性,通道可以由多个网络连接组成。交换机通过初始化到控制器的连接来创建一个到控制器的通道(见6.3.1)。一些交换机实现时可能允许一个控制器连接到交换机,这种情况下,交换机通常应保证安全的连接,以防止没有授权的连接。6.3.1连接建立交换机必须能够与一个用户可配置IP地址(否则是固定的)的控制器建立连接,连接使用用户指定的一个端口或是默认端口。如果交换机与控制器的IP地址进行配置连接,那么交换机启动了一个标准的TLS或TCP连接。Openflow通道的流量不通过Openflow流水线。因此,交换机必须在流表检查之前就必须区分输入流量。当Openflow连接初次建立之时,连接的每一方必须立即发送携带版本字段的OFPT_HELLO消息,版本代表发送者支持的最高的OpenFlow协议版本。这个Hello消息可能含有一些可选内容来帮助建立连接(见7.5.1)。一旦接收到消息,接收方须立即计算出使用的协议版本。如果发送和接收的Hello消息都包含OFPHET_VERSIONBITMAP的hello元素,并且如果这些位图有一些共同的位设置,那双方协商的协议是最高版本的。否则,协商版本是接收到的版本字段中较小版本数字。如果接收方支持协商版本,那么连接可行。否则,接收方必须回应一个OFPT_ERROR消息,此消息带有OFPET_HELLO_FAILED的类型字段,OFPHFC_INCOMPATIBLE的字段以及一个解释数据状态的随机ASCII字符串,然后终止连接。在交换机和控制器交换过OFPT_HELLO消息并且有共同的版本数字之后,连接设置就完成了,标准的Openflow消息能够在连接之上交换。首先,控制器发送一个OFPT_FEATURES_REQUEST消息来取得交换机的数据路径ID(见7.3.1).6.3.2连接中断当交换机与所有的控制器丢失连接,会导致echo请求超时,TLS(安全传输协议)握手超时,或者其他的连接失败,交换机根据当前运行状态和配置,必须立即进入“失败安全模式”或者“失败模式”。在失败安全模式下,交换机行为唯一的改变就是丢弃发向控制器的包和消息。流表项应在“失败安全模式”下依据定时设置继续会发生超时现象。在“失败模式”下,交换机使用OFPP_NORMAL保留端口处理所有的包。换机话说,就是交换机作为传统以太网的交换机和路由器。“失败模式”一般只在Hybrid交换机上存在(见5.1)。当再一次连接控制器时,已有的流表项将保留。如果有必要的话,控制器可删除所有的流表项。交换机第一次启动时,它会运行在“失败安全模式”或者“失败模式”,直到它成功的连接到控制器。启动时流表项的默认设置内容不在本Openflow协议之内。6.3.3加密交换机和控制器可通过TLS连接(安全传输层协议)通信。交换机启动时初始化TLS连接来连接控制器,TLS连接默认TCP端口是6633。交换机和控制器通过交换由位置专一密钥签名的证书,来相互鉴权。每个交换机必须是用户可配置的,并携带控制器鉴权的证书(控制器证书)和另一个证书向控制器鉴权(交换机证书)。交换机和控制器可选择用普通TCP来互通,此TCP连接默认位于TCP端口6633,由交换机发起和初始化。当使用默认的普通TCP连接,推荐使用其他安全措施来防止窃听,伪装控制器以及其他Openflow通道上的攻击。6.3.4多控制器交换机可能与一个或多个控制器建立通信。多控制器模式可靠性更好,如果一个控制器连接失败,交换机还是能够继续运行在Openflow模式中的。控制器的hand-over(切换)机制由控制器自己管理,这能够使其从失败中快速恢复或者使其负载平衡。控制器通过现有规范之外的模式来调节对交换机的管理。多控制器的目的是帮助同步控制器的传输。多控制器的功能基于控制器容错和负载平衡,而不是基于Openflow协议之外的虚拟化。当Openflow操作启动,交换机必须连接到所有与其配置相关的控制器,并且尽力保持与他们的连接。许多控制器发送controller-to-swith命令到交换机,有关此命令的回复消息或错误消息必须被返回通过相关的控制器连接。异步消息可能发送给多个控制器,为每一个Openflow通道复制一个消息,当控制器允许时就发出去。控制器默认的身份是OFPCR_ROLE_EQUAL。以这种身份,控制器能够完全访问交换机,这对其他控制器是一样的。默认地,控制器接收交换机所有的异步消息(比如包输入消息,流删除)。控制器发送controller-to-swith命令来改变交换机的状态。交换机与众控制器之间互不干涉,也不进行资源共享。控制器可要求更换身份到OFPCR_ROLE_SLAVE。这样,控制器以只读方式接入到交换机。控制器默认不接收交换机的异步消息,除了端口状态消息。控制器拒绝执行发送数据或改变交换机状态的controller-to-swith命令,例如,OFPT_PACKET_OUT,OFPT_FLOW_MOD,OFPT_GROUP_MOD,OFPT_PORT_MOD,OFPT_TABLE_MOD请求,以及OFPMP_TABLE_FEATURES非空体复合请求必须拒绝。如果控制器发送以上命令中的一个,那么交换机必须返回一个携带OFPET_BAD_REQUEST类型字段和OFPBRC_IS_SLAVE代码段的OFPT_ERROR消息。其他controller-to-swith消息,例如OFPT_ROLE_REQUEST,OFPT_SET_ASYNCandOFPT_MULTIPART_REQUEST这些查询数据的消息,应该正常进行处理。控制器也可更换身份为OFPCR_ROLE_MASTER。这个角色与OFPCR_ROLE_EQUAL相似的,可完全访问交换机,不同的是,控制器要确保它的角色是唯一的。当控制器换到此身份时,交换机让OFPCR_ROLE_MASTER控制器改变为OFPCR_ROLE_SLAVE,但是不会影响到OFPCR_ROLE_EQUAL控制器。当交换执行身份切换操作时,没有消息生成发送发到正进行身份切换的控制器(大多数情况下控制器不再可到达)。每个控制器会发送OFPT_ROLE_REQUEST消息给交换机让其知道自己的身份,交换机必须记住每个连接控制器的身份。控制器可能随时改变身份,只要在当前消息中提供generation_id。身份请求消息提供了一种轻量级机制来帮助控制器管理选举进程,控制器互相协调来配置自己身份。交换机不能直接的改变控制器的状态,这是由另一个控制器发出的消息作用的结果。任何的从控制器或者对等控制器(equalcontroller)可选择自己的主控制器。交换机可能同时连接到多个对等控制器,或多个从控制器,但最多连接一个主控制器。主控制器和对等控制器能完全改变交换机的状态,控制器没有分割交换机的机制。如果主控制器需要作为唯一能改变交换机的控制器,其它控制器应该全是从控制器,而不能有对等控制器。控制器可控制在Openflow通道中传输的异步消息的类型,并改变上述的默认值。通过异步配置消息(6.1.1)列出需要使能或过滤的消息类型的所有原因。通过这个特性,不同的控制器可以接收不同的通知,主控制器可以选择性的禁用其不关心的通知,从控制器可以启动它想监控的通知。为了检测主从控制器切换时产生的无序消息,OFPT_ROLE_REQUEST消息包含了一个位序列字段,generation_id,来标识主控身份。作为主控选举机制的一部分,控制器(或者第三方)协调generation_id的分配。generation_id是单调递增的计数器:每次主控关系改变时,会分配一个新的(更大的)generation_id,例如,每当指定一个新的主控制器,generation_id会增加。当接收到身份是OFPCR_ROLE_MASTER和OFPCR_ROLE_SLAVE控制器发来的OFPT_ROLE_REQUEST消息,交换机必须将其包含的generation_id消息与之前最大的generation_id比较,若较小的话,则丢弃。交换机必须用错误消息回应,错误消息的类型是OFPET_ROLE_REQUEST_FAILED,代码是OFPRRFC_STALE。下面的伪代码描述了交换机处理generation_id的行为。交换机的启动:generation_is_defined=false;接收到身份是OFPCR_ROLE_MASTER和OFPCR_ROLE_SLAVE控制器发来的OFPT_ROLE_REQUEST消息,并携带一个给定的generation_id,代码GEN_ID_X:if(generation_is_definedANDdistance(GEN_ID_X,cached_generation_id)<0){;;}else{cached_generation_id=GEN_ID_X;generation_is_defined=true;;}distance()作为计算卷序列号距离的操作定义如下:distance(a,b):=(int_t)(a-b);I.e.distance()表示序列号之间无符号的差异,被解读为一个有符号的二进制补码值。当a大于b且满足小于“序列长度的一半”,则为正值,若a小于b则为负值。如果消息请求身份是对等身份,交换机则忽略generation_id,因为generation_id是用来协调主从身份转换的。6.3.5辅助连接默认情况下,Openflow通道是一个的网络连接。通道可能由一个主连接和多个辅连接组成。辅助连接由交换机创建,有利于改善交换机的性能和充分利用交换机的并行性。交换机到控制器的每个连接,都由DatapathID和AuxiliaryID来确认。主连接必须设置AuxiliaryID为0,而辅连接须有一个非零的AuxiliaryID和相同的DatapathID。辅助连接必须使用和主连接相同的IP地址,但是可以使用不同的传输方式,例如,TLS,TCP,DTLS或者UDP,这取决于交换机的配置。辅助连接应该有和主连接相同的目标IP地址和相同的传输目的端口,除非交换机配置了指定值。控制器必须识别带有非零AuxiliaryID的连接,并绑定到具有相同DatapathID的主连接。交换机不能在主连接完成建立之前启动辅连接(见6.3.1),因为只有确保主连接存在,辅连接才会被设置和维持(见6.3.1)。辅连接的建立和主连接是相同的。如果交换机发现到控制器的主连接断了,则必须立即关闭所有到那个控制器的辅连接,这样使控制器正确的解决DatapathID的冲突。交换机和控制器必须接收所有连接的全部消息类型和子类型:主连接和辅连接不会一个指定的消息类型和子类型。但是,在不同的连接上不同的消息类型处理性能可能会不同。交换机可能以不同的优先级来处理辅连接,例如优先级高的就优先处理其消息。使用OpenFlow配置协议的交换机,可能随机的赋予辅连接优先级。Openflow请求的回应必须用相同的连接返回。连接之间是不同步的,不同连接的消息可能以任意的顺序来处理。一个屏障消息仅用于使用它的连接(见6.2)。使用DTLS或UDP的辅连接可能丢失或重排消息,Openflow在辅连接上不提供排序或传输保证。如果消息必须要按序处理,那么他们则通过相同的连接发送,此连接不重新对包排序,并且使用屏蔽消息。在整个运行期间,控制器自由的使用各种交换机连接来发送消息,但是为了最大化交换机的性能,提出以下建议:1.非包出消息(流模型,统计请求)的控制器消息应通过主连接传送。2.含有包入消息的包出消息,应从包入的连接发送出去。3.其他的包出消息通过辅连接发送,通过某种机制保证同一个流的数据包映射到相同的连接。4.如果需要的辅连接找不到,控制器应该利用主连接。交换机可自由的使用不同的控制器连接来发送消息,尽管有下面的指导建议:1.所有非包出的Openflow消息应通过主连接传送。2.所有包出消息通过不同的辅连接发送,但通过某种机制保证同一个流的数据包映射到相同的连接。建立在不可靠传输(UDP,DTLS)之上的辅连接有额外的和规则,这些和规则不适用于TCP,TLS。不可靠的辅连接支持的消息类型有如下:OFPT_HELLO,OFPT_ERROR,OFPT_ECHO_REQUEST,OFPT_ECHO_REPLY,OFPT_FEATURES_REQUEST,OFPT_FEATURES_REPLY,OFPT_PACKET_IN,OFPT_PACKET_OUT和OFPT_EXPERIMENTER,其他类型的不被规范支持。在不可靠的辅连接上,HELLO消息在连接启动时被发送用来设置连接(见6.3.1)。如果Openflow设备在接收到一个HELLO消息之前,接收来自不可靠辅连接的另一个消息,则设备要么假定连接已合理设置,并且使用来自消息的版本号,要么返回一个携带OFPET_BAD_REQUEST类型和FPBRC_BAD_VERSION代码的消息。如果Openflow设备从辅连接之上,接收到一个携带OFPET_BAD_REQUEST类型和FPBRC_BAD_VERSION代码的消息,那么它必须发送一个新的Hello消息或者终止这个不可靠的辅连接(连接可能稍后重试)。如果辅连接上的消息在所选时间(低于5秒)之内没有被接收,则设备必须发送一个新的Hello消息或者终止不可靠的辅连接。如果在发送一个FeatureRequest消息之后,控制器在所选时间之内没有收到一个FeatureReply消息,则设备必须发送一个新的FeatureRequest消息或者终止不可靠的辅连接。如果在接收到消息之后,设备在30秒内的所选时间没有接收任何消息,那么设备就终止不可靠的辅连接。如果设备接收到一个已中止的不可靠辅连接消息,设备必须假定他是一个新的连接。使用不可靠的辅连接的Openflow设备,应尽可能遵循RFC05的规范。6.4流表修改信息流表修改信息有以下类型:enumofp_flow_mod_command{OFPFC_ADD=0,/*新流表.*/OFPFC_MODIFY=1,/*修改所有匹配表.*/OFPFC_MODIFY_STRICT=2,/*严格匹配通配符和修改条目优先级.*/OFPFC_DELETE=3,/*删除所有匹配表.*/OFPFC_DELETE_STRICT=4,/*严格匹配通配符和删除条目优先级.*/};携带OFPFF_CHECK_OVERLAP标志设置的添加请求(OFPFC_ADD),交换机必须首先检查请求表中任何重叠流表项。如果一个数据包同时匹配两个,而且两个项有相同的优先级,两个流表项就重叠。如果一个重叠冲突出现在已有流表项和添加请求之间,交换机必须拒绝添加,并且回馈一个OFPET_FLOW_MOD_FAILED类型和OFPFMFC_OVERLAP代码的ofp_error_msg。对于没有重叠的添加请求,或者他们没有重叠的检查,交换机必须在请求表中插入流表项。如果在请求表中已经有了含有完全相同的匹配字段和优先级的一个流表项,则已有的流表项,包括其生存期,必须从表中删除,新的流表项将被添加。如果设置OFPFF_RESET_COUNTS标志,流表项计数器必须清零,否则他们应该从替换的流表项中复制。作为添加请求的一部分,流表项删除不会生成flow-removed消息;如果控制器想要一个flow-removed消息,它应当在添加一个新流表项之前对旧的流表项发送一个明确的删除请求。关于修改请求(OFPFC_MODIFY或OFPFC_MODIFY_STRICT),如果匹配项出现在表中,表项中的指令字段更新为请求的值,然而它的cookie,idle_timeout,hard_timeout,标记,计数器,和生存字段不发生改变。如果OFPFF_RESET_COUNTS标记被设定,流表项计数器必须被清零。关于修改请求,如果当前请求表中没有流表项匹配这个请求,则没有错误记录,也没有流表修改发生。对于删除请求(OFPFC_DELETE或OFPFC_DELETE_STRICT),如果一个匹配项出现在表中,它必须被删除,如果有OFPFF_SEND_FLOW_REM标记集,它必须发生一个流移除信息。对于删除请求,如果当前在请求表中没有流表项来匹配请求,则没有错误记录,也没有流表修改发生。修改和删除流flow-mod命令有非严格的版本(OFPFC_MODIFYandOFPFC_DELETE)和严格的版本(OFPFC_MODIFY_STRICTorOFPFC_DELETE_STRICT),在严格的版本中,匹配字段集,所有匹配字段,包括他们的掩码、优先级,是和表项严格匹配的,只有一个相同的流表项被修改或删除。比如,发送一个移除表项的信息,如果没有字段能够匹配,则OFPFC_DELETE命令就要从表中删除所有的流表项,而OFPFC_DELETE_STRICT命令只会删除一个应用在指定优先级数据包上的流表项。关于非严格修改和删除命令,与流模式描述相匹配的所有流表项都会被修改和删除。在非严格版本,当流表项正好匹配或者比流模式命令描述的更多,一个匹配就会产生。在流模式中失配字段变为通配的,字段掩码是有效的,比如优先级等其他的流模式字段则被忽略。比如,如果一个OFPFC_DELETE命令去删除目标端口为80的所有流表项,那么通配所有匹配字段的流表项将不会被删除。然而,通配所有字段的一个OFPFC_DELETE命令将会删除一个匹配端口80的表项。同样的解释混合通配符和精确匹配字段也适用于单个和汇聚流数据请求。目标组或输出端口可以有选择地过滤删除命令。如果输出端口字段包含一个值除了OFPP_ANY。匹配时它引入一个约束,这个约束是,每个匹配流表项必须包含一个针对指定端口的输出行动。这个约束只对直接与流表项关联的行动进行。换句话说,交换机不能通过点到组的行动集递归,这可能已经匹配输出操作。out_group,如果不同于OFPG_ANY,对组引入了类似的行动。这些字段被OFPFC_ADD,OFPFC_MODIFY和OFPFC_MODIFY_STRICT消息忽略。删除和修改命令也能够通过cookie值过滤。如果cookie-mask字段包含一个值而不是0.这种约束就是流模式cookie字段中cookie_mask指定的位和流条目的cookie值必须相同。换句话说(flow_entry.cookie&flow_mod.cookie_mask)==(flow_mod.cookie&flow_mod.cookie_mask)。删除命令针对table_id可使用OFPTT_ALL值来表示匹配的流表项将被从所有流表中删除。如果流表修改消息指定一个无效的table_id。交换机必须发送一个带有OFPET_FLOW_MOD_FAILED类型和OFPFMFC_BAD_TABLE_ID代码的ofp_error_msg消息。如果流修改消息在添加和修改请求中对table_id指定了OFPTT_ALL,交换机必须发送相同的错误消息。当向请求表中添加进入的流表项时,交换机不能在请求表中找到空间。交换机必须发送一个带有OFPET_FLOW_MOD_FAILED类型和OFPFMFC_TABLE_FULL代码的ofp_error_msg消息。如果流模式消息中请求指令不明白,交换机必须发送一个带有OFPET_BAD_INSTRUCTION类型和OFPBIC_UNKNOW_INTS代码的ofp_error_msg消息。如果流模式消息中请求指令是不受支持的,交换机必须发送一个带有OFPET_BAD_INSTRUCTION类型和OFPBIC_UNSUP_INTS代码的ofp_error_msg消息。如果请求指令包含Goto-Table和next-table-id,指向一个无效的表,交换机必须返回一个带有OFPET_BAD_INSTRUCTION类型和OFPBIC_BAD_TABLE_ID代码的ofp_error_msg消息。如果请求指令包含Write-Metadata,而且元数据值或元数据掩码的值是不支持的,交换机必须返回一个带有OFPET_BAD_INSTRUCTION类型和OFPBIC_UNSUP_METADATA或OFBIC_UNSUP_METADATA_MASK代码的ofp_error_msg消息。。如果流模式消息指定的一个字段,匹配时在表中是不支持的,交换机必须返回一个带有OFPET_BAD_MATCH类型和OFPBIC_BAD_FIELD代码的ofp_error_msg消息。如果流模式消息指定的一个字段,匹配时不止一次,交换机必须返回一个带有OFPET_BAD_MATCH类型和OFPBIC_DUP_FIELD代码的ofp_error_msg消息。如果匹配交换机流消息指定字段,但未能指定相关的先决条件,例如指定一个IPv4地址而没有匹配EtherType到0x800,交换机必须返回一个携带OFPET_BAD_MATCH类型和OFPBMC_BAD_PREREQ代码的ofp_error_msg。流模式特定的数据链路或网络地址一个随机位掩码匹配,如果交换机不能支持,交换机必须返回一个带有OFPET_BAD_MATCH类型和OFPBMC_BAD_DL_ADDR_MASK或OFPBMC_BAD_NW_ADDR_MASK的ofp_error_msg消息。如果bitmasks中指定不支持数据链接和网络地址就应使用OFPBMC_BAD_DL_ADDR_MASK。如果流模式指定另一个字段的一个随机位掩码匹配不能支持,交换机必须返回一个带有OFPET_BAD_MATCH类型和OFPBMC_BAD_MASK代码的ofp_error_msg消息。如果流模式指定值不能匹配,例如,一个大于4095的VLANID,与一个非保留值或两个高位比特设置一个的DSCP值,交换机必须返回一个带有OFPET_BAD_MATCH类型和OFPBMC_BAD_VALUE代码的ofp_error_msg消息。如果任意行动作用到交换机的一个不再有效端口,交换机必须返回一个带有OFPET_BAD_ACTION类型和OFPBAC_BAD_OUT_PORT代码的ofp_error_msg消息。如果有关的端口也许在将来会是有效的,例如当一个linecard添加到传统交换机,或动态添加一个端口到软交换机,交换机要么丢弃发送到该端口的数据包,要么立即返回一个OFPBAC_BAD_OUT_PORT错误并拒绝此流模式。如果流模式消息中的一个行动涉及到一个交换机没有定义的组,或是一个保留组比如OFPG_ALL,交换机必须返回一个带有OFPET_BAD_ACTION类型和OFPBAC_BAD_OUT_GROUP代码的ofp_error_msg消息。如果流模式消息的行动有一个无效的值,例如SetVLANID的行动值大于4095,或用无效Ethertype进行Push行动,交换机必须返回一个带有OFPET_BAD_ACTION类型和OFPBAC_BAD_ARGUMENT代码的ofp_error_msg消息。如果一个流模式消息中的行动执行一个与匹配不一致的操作,比如,一个弹出VLAN行动,而匹配没有指定VLAN,或使用通配Ethertype的匹配来设置IPv4地址,交换机可以选择拒绝此流模式并立即返回一个带有OFPET_BAD_ACTION类型和OFPBAC_MATCH_INCONSISTENT代码的ofp_error_msg消息。任何不一致的行动对匹配数据包的影响没有定义,强烈建议控制器避免产生可能引起不一致行动的表项组合。如果一个行动列表有一系列的行动,而交换机不能按其指定次序支持,交换机必须返回一个带有OFPET_BAD_ACTION类型和OFPBAC_UNSUPPORTED_ORDER代码的ofp_error_msg消息。在流模式消息处理期间发生任何其它的错误,交换机可能会返回一个带有OFPET_FLOW_MOD_FAILED类型和OFPFMC_UNKNOWN代码的ofp_error_msg消息。6.5组表修改信息组表修改信息有以下类型:/*组命令*/enumofp_group_mod_command{OFPGC_ADD=0,/*新组.*/OFPGC_MODIFY=1,/*修改所有匹配组.*/OFPGC_DELETE=2,/*删除所有匹配组.*/};组可能含有零个或零个以上的储存段。没有储存段的组将不会更改与包有关的行动集。如果交换机支持的话,一个含有储存段的组他们本身也可转向其他的组。行动集对每个储存段要验证,使用的规则就是与流模式相同的规则(6.4节),并进行组指定的校验。如果在一个储存段中一个行动是无效的或不支持,交换机应当返回一个ofp_error_msg和OFPET_BAD_ACTION类型,以及相应的错误代码。(见6.4)对于add请求(OFPGC_ADD),如果组表中已经有了指定标识符的组表项,交换机就会拒绝添加组表项。并且发送一个带有OFPET_GROUP_MOD_FAILED类型和OFPGMFC_GROUP_EXISTS代码的ofp_error_msg消息。对于修改请求(OFPGC_MODIFY),如果组表中已经有了指定标识符的组表项,那么包括它的类型和行动储存段,必须被移除,然后新组表项被添加。如果指定标识符的组中此组表项不存在,交换机必须拒绝此流模式并发送一个带有OFPET_GROUP_MOD_FAILED类和OFPGMFC_UNKNOWN_GROUP代码的ofp_error_msg消息。如果一个指定的组类型是无效的,(比如:指定组类型中没有定义的像权重这样的字段)交换机必须拒绝添加组表项,并且发送一个ofp_error_msg伴随OFPET_GROUP_MOD_FAILED类型和OFPGMFC_INVALID_GROUP代码。如果交换机在所选组中不支持非均等负荷共享(存储段的权重不等于1),必须拒绝添加这个组表项,必须发送一个带有OFPET_GROUP_MOD_FAILED类和OFPGMFC_WEIGHT_UNSUPPORTED代码的ofp_error_msg消息。如果由于缺少空间,交换机不能添加到来的组表项,交换机必须发送一个带有OFPET_GROUP_MOD_FAILED类和OFPGMFC_OUT_OF_GROUPS代码的ofp_error_msg消息。如果由于组储存段数量的约束(硬件或其他原因),一个交换机不能添加进来的组表项,交换机必须发送一个带有OFPET_GROUP_MOD_FAILED类和OFPGMFC_OUT_OF_BUCKETS代码的ofp_error_msg消息。如果由于不支持推荐的活动配置,交换机不能添加组,交换机必须发送一个带有OFPET_GROUP_MOD_FAILED类和OFPGMFC_WATCH_UNSUPPORTED代码的ofp_error_msg消息。这包括为不支持活动性的组指定watch_port或watch_group,或对watch_port中指定不支持活动性的端口,或对watch_group中指定不支持活动性的组。对于删除请求(OFPGC_DELETE),如果所标识组的组表里没有组表项,就不会记录错误,也不会发生组表修改。否则,组被删除,包含在组行动中所有组流表项也会被删除。组类型不需要在删除请求中指定。删除不同于没有储存段的添加或修改,以后试图添加组标识符不会造成组已存在的错误。如果希望使用它有效地删除保留在流表项里的组,组可以通过发送一个无指定储存段的修改来删除。用单个消息删除所有组的话,需要指定OFPG_ALL作为组值。如果交换机支持的话,组可以串联起来,至少有一组指向另一组,或有更复杂的结构。例如一个快速重路由组可能有两个储存段,每一个指向选择的组。如果一个交换机不支持串联组的组,它必须发送一个带有OFPET_GROUP_MOD_FAILED类型和OFPGMFC_CHAINING_UNSUPPORTED代码的ofp_error_msg消息。一个交换机可支持检测组成链时不能形成循环:如果组将创建一个转发循环,交换机必须拒绝组并且必须发送一个带有OFPET_GROUP_MOD_FAILED类型和OFPGMFC_LOOP代码的ofp_error_msg消息。如果交换机不支持这样的检查,则转发行为就是未定义的。一个交换机可支持检测被其它组转发的组没有删除:如果交换机由于组关联另一个组而不能删除,必须拒绝删除组的表项,必须发送一个带有OFPET_GROUP_MOD_FAILED类型和OFPGMFC_CHAINED_GROUP代码的ofp_error_msg消息。如果交换机不支持这样的检查,则转发行为就是未定义的。若支持组的快速故障切换需要在线监测,以确定要处理的指定储存段。其它组类型不需要实现在线监视,但可以选择应用它。如果一个交换机不能实现在线检查组中的任意储存段,它必须拒绝组并返回一个错误。确定活跃的规则包括:一个端口被认为是活的如果它端口状态设置为OFPPS_LIVE标志。端口活性可由交换机OpenFlow部分之外的代码管理,代码由OpenFlow规范之外来定义,如生成树或KeepAlive机制。如果交换机某个端口活跃机制认为端口不活跃,此端口就必须不能认为活跃(OFPPS_LIVE标志必须未设置),或者端口配置位OFPPC_PORT_DOWN表示端口已关闭,或者端口状态OFPPS_LINK_DOWN显示链接已拆除。如果watch_port不是OFPP_ANY而且端口监测是活跃的,或者watch_group不是OFPG_ANY而且组监测是活跃的,则存储段就认为活跃。如果至少一个储存段是活跃的则一个组就认为是活跃的。通过监控不同端口的状态控制器可以推断组的活性状态。6.6测量修改信息测量修正信息有以下类型:/*测量指令*/enumofp_meter_mod_command{OFPMC_ADD,/*新测量.*/OFPMC_MODIFY,/*修改指定的测量.*/OFPMC_DELETE,/*删除指定的测量.*/};对于添加请求(OFPMC_ADD),如果指定测量标识符的测量项已经存在,交换机必须拒绝添加测量项,并且必须发送一个含有OFPET_METER_MOD_FAILED类和OFPMMFC_METER_EXISTS码的ofp_error_msg消息。对于修改请求(OFPMC_MODIFY),如果指定测量标识符的一个测量项已经存在,这个测量项,包括其带宽,必须删除,添加新测量项。如果指定表标识符的测量项不存在,那么交换机必须拒绝metermod并且发送一个含OFPET_METER_MOD_FAILED类和OFPMMFC_UNKNOWN_METER码的ofp_error_msg消息。如果交换机由于缺少空间而不能添加进入的测量项,交换机必须发送一个带有OFPET_METER_MOD_FAILED类和OFPMMFC_OUT_OF_METERS代码的ofp_error_msg消息。由于带宽数量的约束(硬件和其他方面),交换机不能添加进入的测量项,必须拒绝添加测量项,并且发送一个带有OFPET_METER_MOD_FAILED类和OFPMMFC_OUT_OF_BANDS码的ofp_error_msg消息。对于删除请求(OFPMC_DELETE),如果指定测量标识符的测量项没有存在,就没有错误记录,也没有表发生修改。否则,将删除测量,在指令集中包含此测量的所有流也会被删除。对于delete请求只需要指定测量标识符,其他字段如带宽可以省略。用OFPM_ALL作为测量值的单个消息可删除所有的测量。虚拟的测量永远不会删除,当删除所有的测量时,也不会消除。7、openflow协议Openflow交换机规范的核心就是建立Openflow协议消息的结构体。下面描述的结构体,定义和枚举都是源于文件include/openflow/openflow.h,此文件是openflow标准规范的一部分。所有结构体都是用填充和8字节来对齐,并且由声明核查。所有消息都是以big-endian格式发送。7.1openflow头部每个openflow消息都是以head开头/*所有OpenFlow的头部*/structofp_header{uint8_tversion;/*OFP_VERSION.协议版本*/uint8_ttype;/*一个OFPT_常数*/uint16_tlength;/*包含头部的长度*/uint32_txid;/*与包有关的事件ID,回复配对请求时使用相同的ID*/};OFP_ASSERT(sizeof(structofp_header)==8);openflow版本指正在使用的协议版本,早期阶段的openflow草稿中,用最高位表示实验版本,低位表明协议版本号。现在介绍的协议1.3.2,版本是0x04。长度字段表明了消息的总长度,因此并没有用额外的帧标识去区分每个帧。类型可以有以下值:enumofp_type{/*不可改变的消息*/OFPT_HELLOOFPT_ERROR=0,=1,/*对称消息*//*对称消息*/=2,=4,/*对称消息*//*对称消息*//*对称消息*/OFPT_ECHO_REQUESTOFPT_EXPERIMENTER/*交换机配置消息*/OFPT_ECHO_REPLY=3,OFPT_FEATURES_REQUEST=OFPT_FEATURES_REPLY=OFPT_GET_CONFIG_REQUESTOFPT_GET_CONFIG_REPLYOFPT_SET_CONFIG/*异步消息*/OFPT_PACKET_IN=5,/*6,/*=控制器/交换机消息*/控制器/交换机消息*/=7,/*控制器/交换机消息*/8,/*控制器/交换机消息*/控制器/交换机消息*/9,/*=10,/*异步消息*/OFPT_FLOW_REMOVED=11,/*异步消息*/OFPT_PORT_STATUS=12,/*异步消息*//*控制器命令消息*/OFPT_PACKET_OUT=13,控制器/交换机消息*/OFPT_FLOW_MODOFPT_GROUP_MODOFPT_PORT_MODOFPT_TABLE_MOD/*复合消息*/OFPT_MULTIPART_REQUEST=18,控制器/交换机消息*/OFPT_MULTIPART_REPLY=19,控制器/交换机消息*//*屏障消息(见6.1.1)*/OFPT_BARRIER_REQUEST=20,控制器/交换机消息OFPT_BARRIER_REPLY/*队列配置消息.*/OFPT_QUEUE_GET_CONFIG_REQUEST=22,/*控制器/交换机消息*/OFPT_QUEUE_GET_CONFIG_REPLY=23,/*控制器/交换机消息*/*/=21,控制器/交换机消息*/=14,控制器/交换机消息*/=15,控制器/交换机消息*/=16,控制器/交换机消息*/=17,控制器/交换机消息*//*控制器角色改变请求消息*/OFPT_ROLE_REQUEST=24,控制器/交换机消息*/OFPT_ROLE_REPLY=25,控制器/交换机消息*//*异步消息配置*/OFPT_GET_ASYNC_REQUEST=26,控制器/交换机消息*/OFPT_GET_ASYNC_REPLY=27,控制器/交换机消息OFPT_SET_ASYNC=28,控制器/交换机消息*/*/*/*//*测量器和速率器配置消息OFPT_METER_MOD};7.1.1填充=29,控制器/交换机消息大多数openflow消息都包含填充字段,各种类型消息和各种共有的结构体中都有。这些填充字段实际上它们的名字以pad开始,填充字段的目的就是使多字节实体和实际处理器边界对齐。所有消息有结构体都是比特对齐。其它类型则根据需要对齐,例如32位整数在32位边界中对齐。一个填充规则例外就是OXM匹配字段,它从不进行填充(7.3.2)。通常openflow消息除非明确说明,否则并不填充;另一方面,大多数共有的结构体都在结尾填充。填充字段应设置为零。一个openflow实现必须能接受填充字段中设置的任何值,而且必须忽略填充域中的内容。7.2共有结构体本节介绍各种消息类型使用的结构体。7.2.1端口结构体Openflow流水线通过端口收发数据包。交换机可以定义物理端口和逻辑端口,openflow规范定义一些保留端口(4.1)。物理端口,交换机定义的逻辑端口,OFPP_LOCAL保留端口结构体描述如下:/*端口说明*/structofp_port{uint32_tport_no;uint8_tpad[4];uint8_thw_addr[OFP_ETH_ALEN];uint8_tpad2[2];/*Aligntobits.*/charname[OFP_MAX_PORT_NAME_LEN];/*Null-terminated*/uint32_tconfig;/*BitmapofOFPPC_*flags.*/uint32_tstate;/*BitmapofOFPPS_*flags.*//*BitmapsofOFPPF_*thatdescribefeatures.Allbitszeroedif*unsupportedorunavailable.*/uint32_tcurr;/*Currentfeatures.*/uint32_tadvertised;/*Featuresbeingadvertisedbytheport.*/uint32_tsupported;/*Featuressupportedbytheport.*/uint32_tpeer;/*Featuresadvertisedbypeer.*/uint32_tcurr_speed;/*Currentportbitrateinkbps.*/uint32_tmax_speed;/*Maxportbitrateinkbps*/};OFP_ASSERT(sizeof(structofp_port)==);Port-no唯一标识交换机内的端口。hw_addr通常是端口MAC地址;OFP_ETH_ALEN为6.名字字段是一个空终止字符串,包含一个可读接口名称。OFP_MAC_PORT_NAME_LEN值为16.配置字段描述端口的管理设置,有以下结构体:/*物理端口的行为标志。在ofp_port用这个标志描述当前端口配置。用来设定端口行为。*/enumofp_port_config{OFPPC_PORT_DOWN=1<<0,/*端口在管理下关闭*/OFPPC_NO_RECV=1<<2,/*丢弃端口接收的所有包*/OFPPC_NO_FWD=1<<5,/*丢弃所有转发给该端口的包*/OFPPC_NO_PACKET_IN=1<<6/*不向端口发送packet-in消息*/};这个OFPPC_PORT_DOWN位表明端口在管理下断开,OpenFlow不应该使用。这个OFPPC_NO_RECV位表明从哪个端口收到的包应该忽略。这个OFPPC_NO_FWD位表明不应该发送包给这个端口。这个OFPPFL_NO_PACKET_IN位表明这个端口的包发生漏表行为,不会触发packet-in消息给控制器。一般来说,端口配置位由控制器设置并且不被交换机改变。这些位在交换机实现协议(如:STP或者BFD)时非常有用。如果端口配置位被交换机通过其他管理接口改变了,交换机发送一个OFPT_PORT_STATUS消息通知控制器发生了改变。(STP:生成树协议BFD:快速故障检测标准协议)状态字段描述了端口的内部状态,有以下结构:/*物理端口的当前状态,并不是由控制器配置的*/enumofp_port_state{OFPPS_LINK_DOWN=1<<0,/*目前没有物理连接*/OFPPS_BLOCKED=1<<1,/*端口堵塞*/OFPPS_LIVE=1<<2,/*有效的快速故障备份组*/};端口状态位代表物理连接或openflower以外的交换机协议。OFPPS_LINK_DOWN位表明协议连接断开。OFPPS_BLOCKED位表明openflowe以外的交换,例如802.1D生成树协议,防止OFPP_FLOOD端口的使用。所有端口状态位都是只读的,不能被控制器改变。当端口标志改变时,交换机发送OFPT_PORT_STATUS消息通知控制器。端口号使用以下规则:/*端口编号。端口从1开始编号。*/enumofp_port_no{OFPP_MAX=0xffffff00,/*物理端口和逻辑交换端口的最大号码*//*保留OpenFlow端口(假装输出\"ports\").*/OFPP_IN_PORT=0xfffffff8,/*将包从输入端口发出。为了将包发回给输入端口,这个保留端口必须要明确使用。*/OFPP_TABLE=0xfffffff9,/*将包提交给第一个表。NB:这个目的端口只能在packet-out消息中使用*/OFPP_NORMAL=0xfffffffa,/*处理常规的L2/L3交换*/OFPP_FLOOD=0xfffffffb,/*VLAN中所有物理端口,除了输入端口和阻塞的或者链路断开的端口。*/OFPP_ALL=0xfffffffc,/*除了输入端口外的所有物理端口*/OFPP_CONTROLLER=0xfffffffd,/*发给控制器*/OFPP_LOCAL=0xfffffffe,/*本地openflow\"port\".*/OFPP_ANY=0xffffffff/*通配端口只能在流修改(删除)、流统计请求中使用。筛选所*/有流,无论是什么输出端口(包括没有输出端口的流)};Curr,advertised,supported,peer字段表示链路模式(speedandduplexity;10M到10G,全双工、半双工),链路类型(铜/光纤),链路特征(自动协商和暂停)。Curr是当前连接方式、类型、特征;advertised是广播给对方的连接方式、类型、特征;supported是支持的链路方式、类型、特征。Peer是对方的连接方式、类型、特征。端口特征由如下结构体表示:/*数据通道中有效端口的特征.*/enumofp_port_features{OFPPF_10MB_HD=1<<0,/*支持10M半双工速率*/OFPPF_10MB_FD=1<<1,/*支持10M全双工速率*/OFPPF_100MB_HD=1<<2,/*支持100M半双工速率*/OFPPF_100MB_FD=1<<3,/*支持100M全双工速率*/OFPPF_1GB_HD=1<<4,/*支持1Gb半双工速率*/OFPPF_1GB_FD=1<<5,/*支持1Gb全双工速率*/OFPPF_10GB_FD=1<<6,/*支持10Gb全双工速率*/OFPPF_40GB_FD=1<<7,/*支持40Gb全双工速率*/OFPPF_100GB_FD=1<<8,/*支持100Gb全双工速率*/OFPPF_1TB_FD=1<<9,/*支持1Tb全双工速率*/OFPPF_OTHER=1<<10,/*其他速率,不在列表中*/OFPPF_COPPER=1<<11,/*铜线媒质.*/OFPPF_FIBER=1<<12,/*光纤媒质*/OFPPF_AUTONEG=1<<13,/*自动协商*/OFPPF_PAUSE=1<<14,/*暂停*/OFPPF_PAUSE_ASYM=1<<15/*Asymmetricpause.*/};多个标志可同时进行设置。如果没有设置端口速度标志,就会使用max_speed或者curr_speed。curr_speed表明链路当前传输速率,max_speed是最大传输速率,以kbps为单位。将数字四舍五入适应通常的用法。例如,一个光学的10Gb以太网端口应该设置字段为10000000而不是10312500,一个OC_192端口应该将字段设置为100000000而不是9953280.Max_speed表明了链路的最大速率,而curr_speed表明了当前速率。一个有三条链路的LAG端口最大速率为1Gb/s,其中一个端口关闭,一个端口自动协商速率为1Gb/s,一个端口自动协商速率100Mb/s,最大速率为3Gb/s,当前速率为1.1Gb/s。7.2.2队列结构体一个openflow交换机通过简单的排队机制提供有限的QoS服务。一个(或多个)队列可以连接到端口,用来与流表项映射。流表项映射的某个队列,就根据这个队列的配置处理。(注:将队列绑定在某个端口,实现有限的流量控制操作)队列由一个ofp_packet_queue结构体来描述:/*队列的完整描述*/structofp_packet_queue{uint32_tqueue_id;/*指定队列的ID*/uint32_tport;/*队列所属的端口*/uint16_tlen;/*队列的字节长度*/uint8_tpad[6];/*-bit校正*/(与上面的凑成倍数)structofp_queue_prop_headerproperties[0];/*特性列表*/};OFP_ASSERT(sizeof(structofp_packet_queue)==16);一组属性,类型和配置来进一步描述每个队列。enumofp_queue_properties{OFPQT_MIN_RATE=1,/*最低速率保证*/OFPQT_MAX_RATE=2,/*最大速率*/OFPQT_EXPERIMENTER};=0xffff/*实验定义属性*/每个队列属性描述以共同的头部开始:/*队列的一般描述。*/structofp_queue_prop_header{uint16_tproperty;/*OFPQT_.中的某一个*/uint16_tlen;/*属性的长度,包括头部的长度uint8_tpad[4];/*-bitalignemnt.*/};OFP_ASSERT(sizeof(structofp_queue_prop_header)*/==8);一个最小速率的队列特性使用下列结构和字段:/*Min-Rate队列特征描述*/structofp_queue_prop_min_rate{structofp_queue_prop_headerprop_header;/*prop:*/uint16_trate;/*以0.1%为单位;禁止大于1000*/uint8_tpad[6];/*-bit对齐*/};OFP_ASSERT(sizeof(structofp_queue_prop_min_rate)==OFPQT_MIN,len:16.16);如果没有设定速率,则速率设置为OFPQ_MIN_RATE_UNCFG,即0xfff。一个最大速率队列用的结构体和字段如下:/*Max-Rate队列特征描述*/structofp_queue_prop_max_rate{structofp_queue_prop_headerprop_header;/*prop:uint16_trate;/*以0.1%为单位;禁止大于1000*/uint8_tpad[6];/*-bit对齐*/};OFP_ASSERT(sizeof(structofp_queue_prop_max_rate)==OFPQT_MAX,len:16.*/16);如果没有设定速率,则速率为OFPQ_MAX_RATE_UNCFG,即0fff。一个实验队列属性用的结构体和字段如下:/*Experimenter队列特征描述*/{/*prop:OFPQT_EXPERIMENTER,len:structstruct16.*/ofp_queue_prop_experimenterofp_queue_prop_headerprop_header;uint32_t相同*/uint8_tuint8_t};experimenter;/*ExperimenterID与ofp_experimenter_header结构体形式pad[4];data[0];/*/*-bit对齐*/*/实验者定义的数据OFP_ASSERT(sizeof(structofp_queue_prop_experimenter)==16);标准Openflow处理并没有解释其余的实验队列属性,而是由实验者自己定义。7.2.3流匹配结构体一个openflow匹配表是由流匹配头部和一序列0或者一些流匹配字段组成。7.2.3.1流匹配头部用ofp_match结构体描述匹配头部:/*流的匹配字段*/structofp_match{uint16_ttype;/*OneofOFPMT_**/uint16_tlength;/*ofp_match长度(包括填充字段)*//*Followedby:*-Exactly(length-4)(possibly0)bytescontainingOXMTLVs,then*-Exactly((length+7)/8*8-length)(between0and7)bytesof*all-zerobytes*总之,需要时就在ofp_match中进行填充,使其为8的倍数,结构长度对齐。*/uint8_toxm_fields[0];/*0ormoreOXMmatchfields*/uint8_tpad[4];/*Zerobytes-seeaboveforsizing*/};OFP_ASSERT(sizeof(structofp_match)==8);type字段设置为OFPMT_OXM,长度字段为包括所有匹配字段在内的ofp_match结构体的实际长度。OpenFlow有效载荷是一组OXM流匹配字段。/*匹配类型表明正在使用的匹配结构体(构成匹配的字段组)。所有匹配结构体中匹配类型在类型字段的开始。\"OpenFlowExtensibleMatch\"类型与下面介绍的OXMTLV格式相符,并且必须所有交换机都支持。ExtensionsthatdefineothermatchtypesmaybepublishedontheONFwiki.扩展项支持是可选的。*/enumofp_match_type{OFPMT_STANDARD=0,/*不赞成*/OFPMT_OXM=1,/*OpenFlowExtensibleMatch*/};此规范中唯一有效的匹配类型是OFPMT_OXM,不支持OpenFlow1.1匹配类型OFPMT_STANDARD。如果使用另一种匹配类型,匹配字段和有效载荷可能变得会不一样,但是这超出了本规范的范围。7.2.3.2FlowMatchFieldStructures流匹配字段用OpenFlow可扩展的匹配(OXM)格式来描述,即一种简化的形式type-length-value(TLV)。每个OXMTLV长度从5到259(包括全部)字节。OXMTLVs没有相同的长度,也没有采取填充来对齐。一个OXMTLV的前四个字节是头部,下面接的是body部分。一个OXMTLV的头部可看成一个网络字节顺序的32-bit字(见图4)。OXMTLV的头部定义如Table9oxm_class是一个OXM匹配类,包含相关的匹配类型,在7.2.3.3.节有相关介绍。oxm_field是一个class-specfic值,在匹配类里区分某一个匹配类型。oxm_class和oxm_field两者(themost-signicant23bitsoftheheader)都是oxm_type。oxm_type通常表示一个协议的头部字段,例如以太网类型,也可以适用于元数据,例如数据包到达的那个交换机端口。oxm_hasmask定义如果OXMTLV包含位掩码,在7.2.3.5部分有详细介绍。oxm_length是以字节为单位的正整数,表示OXMTLV负荷长度。OXMTLV的长度,包括头部,是精确地4+oxm_length个字节。对于一个指定的oxm_class,oxm_field,andoxm_hasmask值,oxm_length是一个常量。包括只允许软件最低限度的解析OXMTLV的未知类型。(类似的,若指定oxm_class,oxm_field,andoxm_length,则oxm_hasmask是一个常量。)7.2.3.3OXMclasses匹配类型使用OXM匹配类进行了结构化,openflow规范可以区分OXM的两种匹配类,ONF成员类和ONF保留类,使用高位比特区分。高位比特为1是ONF保留类,供openflow规范本身使用。高位比特为0的是ONF成员类,必要时由ONF分配,标识一个ONF成员,并且可任意使用。对ONF成员类的支持是可选的。OXM类定义如下:/*OXMClassIDs.*高位比特区分保留类和成员类*0x0000到0x7FFF的是成员类,由ONF分配*0x8000到0xFFFE的是保留类,用于标准化。*/enumofp_oxm_class{OFPXMC_NXM_0=0x0000,/*与NXM后向兼容*/OFPXMC_NXM_1=0x0001,/*与NXM后向兼容*/OFPXMC_OPENFLOW_BASIC=0x8000,/*OpenFlow基本类*/OFPXMC_EXPERIMENTER=0xFFFF,/*实验者类*/};OPPXMC_OPENFLOW_BASIC类包含openflow匹配域的基本设置(见7.2.3.7)。可选类OFPXMC_EXPERIMENTER用于实验者匹配(见7.2.3.8)。其他ONF保留类用于将来使用,如用于规范的模块化。ONF成员类的前两个OFPXMC_NXM_0和OFPXMC_NXM_1用于与NiciraExtensibleMatch(NXM)规范的后向兼容。7.2.3.4FlowMatch一个zero—length的openflow匹配(即没有OXMTLVs)可以匹配每个包。应被通配的匹配字段都从openflow匹配中忽略。OXMTLV对由openflow匹配进行匹配的包设置:如果oxm_hasmask为0,OXMTLV的body包含该字段的值,称为oxm_value。OXMTLV匹配仅与相应字段等于oxm_value的包相匹配。如果oxm_hasmask为1,oxm_entry的body包含该字段的值(oxm_value),紧接着是一个相同长度的位掩码,叫为oxm_mask。oxm_mask里的每1_bitOXMTLV只能匹配字段与oxm_value相应位相等的包。oxm_mask的0_bit没有这样的。当使用掩码时,oxm_mask中的0_bit与oxm_value中的1_bit一致时产生错误。交换机必须用OFPET_BAD_MATCH类型的消息和OFPBMC_BAD_WILDCARDS事件报告错误。下表总结了相对应的oxm_mask与oxm_value位之间在使用掩码时的约束关系。忽略oxm_mask等同于提供一个全是1-bit的oxm_mask。当有多个OXMTLV时,要满足所有的约束关系:包字段必须匹配openflow匹配中所有OXMTLV的部分。若没有OXMTLV的字段,则通配成ANY,忽略的OXMTLV全部掩码为零。7.2.3.5流匹配字段掩码当oxm_hasmask为1,OXMTLV包含一位掩码并且长度有效地增加一倍,所以oxm_length总是奇数,位掩码在字段值之后,使用相同的方式编码。掩码定义某个指定的位为0,表明与其相应字段相同位的匹配是一种“don’tcare”匹配,而1意味着要精确匹配。一个全0比特oxm_mask等同于彻底忽略OXMTLV,一个全1比特oxm_mask等同于指定oxm_hasmask为0,并且忽略oxm_mask。一些oxm_type不支持掩码的通配符,也就是说,当这些字段被指定时oxm_hasmask必须为0。例如,标识数据包接收的输入端口(接受包的端口)字段可能未被掩码。一些oxm_type不支持掩码通配符,可能只支持特定oxm_mask模式。例如,一些有IPv4地址的字段可能被为CIDR掩码(子网掩码)。个别字段的限定会在规范中详细说明。交换机可能接受规范不允许的oxm_hasmaskoxm_mask值,只要交换机能正确执行对oxm_hasmask或oxm_mask值的支持,交换机必须拒绝尝试创建包含它不支持的oxm_hasmask或oxm_mask值的流表项(见6.4)。7.2.3.6流匹配字段基础给定oxm_type的OXMTLV的存在是受到其他OXMTLV的存在或值的,一般来说,只有当openflow匹配明确地匹配了相应的协议,才能匹配协议的头部字段。例如:只有在另一个表项中oxm_type=OXM_OF_ETH_TYPE,oxm_hasmask=0,并且oxm_value=0x0800的前提下,才允许OXMTLV中xom_type=OXM_OF_IPV4_SRC。也就是说,只有以太网的类型明确设置为IPV4时,IPV4源地址的匹配才被允许。只有在一个表项中oxm_type=OXM_OF_ETH_TYPE,oxm_hasmask=0,oxm_value=0x0800或0x6dd,并且另一个表项中oxm_type=OXM_OF_IP_PROTO,oxm_mask=0,oxm_value=6的前提下,O才允许OXMTLV中xom_type=OXM_OF_TCP_SRC。也就是说,只有当以太网的类型为IP,IP协议为TCP时,在TCP源端口的匹配才允许。只有在一个表项中oxm_type=OXM_OF_ETH_TYPE,oxm_hasmask=0,oxm_value=0x8847或0x8848时,才允许OXMTLV中oxm_type=OXM_OF_MPLS_LABEL。只有在一个表项中oxm_type=OXM_OF_VLAN_VID,oxm_value!=OFPVID=NONE时,才允许OXMTLV中oxm_type=OXM_OF_VLAN_PCP。这些对个别字段的在规范中进行了说明(见7.2.3.7)。交换机实现时可放宽这些。例如,交换机可能在没有任何先决条件的情况下接受。交换机必须拒绝建立试图违反的流表项(见6.4),并且必须处理那些由于缺乏先决条件而不一致的匹配(如,既匹配TCP源端口又匹配UDP目的端口)。由成员(成员类或作为实验者字段)定义的新的匹配字段可为已有匹配字段提供了备用条件。例如,通过替换ETH_TYPE,在可选链路技术(如PPP)上重复使用用已有的IP匹配字段(对于PPP,那可能是一个假设的PPP_PROTOCOL字段)。有条件约束的OXMTLV必须出现在那些作为条件的OXMTLV后面,那些在openflow匹配里的OXMTLV的顺序不受约束。任一指定的oxm_type最多在openflow匹配中出现一次,否则,交换机必须产生一个错误(见6.4)。交换机实现时可放松这个规则,允许在某些情况下多次出现oxm_type,但是,这种匹配行为由具体实现来决定。如果一个流表实现指定的OXMTLV,这个流表必须接受包含其先决条件的有效匹配,即使这个流表并不支持先决条件指定的匹配域的所有可能值。例如,一个流表匹配IPv4源地址,这个流表必须接受以太网类型精确匹配IPV4,但是不需要支持以太网类型匹配其他任何值。7.2.3.7流匹配域本规范为oxm_class=OFPAMC_OPENFLOW_BASIC的匹配字段定义了一个默认的集合,其值如下:/*OXMFlowmatchfieldtypesforOpenFlowbasicclass.*/enumoxm_ofb_match_fields{OFPXMT_OFB_IN_PORT=0,/*Switchinputport.*/OFPXMT_OFB_IN_PHY_PORT=1,/*Switchphysicalinputport.*/OFPXMT_OFB_METADATA=2,/*Metadatapassedbetweentables.*/OFPXMT_OFB_ETH_DST=3,/*Ethernetdestinationaddress.*/OFPXMT_OFB_ETH_SRC=4,/*Ethernetsourceaddress.*/OFPXMT_OFB_ETH_TYPE=5,/*Ethernetframetype.*/OFPXMT_OFB_VLAN_VID=6,/*VLANid.*/OFPXMT_OFB_VLAN_PCP=7,/*VLANpriority.*/OFPXMT_OFB_IP_DSCP=8,/*IPDSCP(6bitsinToSfield).*/OFPXMT_OFB_IP_ECN=9,/*IPECN(2bitsinToSfield).*/OFPXMT_OFB_IP_PROTO=10,/*IPprotocol.*/OFPXMT_OFB_IPV4_SRC=11,/*IPv4sourceaddress.*/OFPXMT_OFB_IPV4_DST=12,/*IPv4destinationaddress.*/OFPXMT_OFB_TCP_SRC=13,/*TCPsourceport.*/OFPXMT_OFB_TCP_DST=14,/*TCPdestinationport.*/OFPXMT_OFB_UDP_SRC=15,/*UDPsourceport.*/OFPXMT_OFB_UDP_DST=16,/*UDPdestinationport.*/OFPXMT_OFB_SCTP_SRC=17,/*SCTPsourceport.*/OFPXMT_OFB_SCTP_DST=18,/*SCTPdestinationport.*/OFPXMT_OFB_ICMPV4_TYPE=19,/*ICMPtype.*/OFPXMT_OFB_ICMPV4_CODE=20,/*ICMPcode.*/OFPXMT_OFB_ARP_OP=21,/*ARPopcode.*/OFPXMT_OFB_ARP_SPA=22,/*ARPsourceIPv4address.*/OFPXMT_OFB_ARP_TPA=23,/*ARPtargetIPv4address.*/OFPXMT_OFB_ARP_SHA=24,/*ARPsourcehardwareaddress.*/OFPXMT_OFB_ARP_THA=25,/*ARPtargethardwareaddress.*/OFPXMT_OFB_IPV6_SRC=26,/*IPv6sourceaddress.*/OFPXMT_OFB_IPV6_DST=27,/*IPv6destinationaddress.*/OFPXMT_OFB_IPV6_FLABEL=28,/*IPv6FlowLabel*/OFPXMT_OFB_ICMPV6_TYPE=29,/*ICMPv6type.*/OFPXMT_OFB_ICMPV6_CODE=30,/*ICMPv6code.*/OFPXMT_OFB_IPV6_ND_TARGET=31,/*TargetaddressforND.*/OFPXMT_OFB_IPV6_ND_SLL=32,/*Sourcelink-layerforND.*/OFPXMT_OFB_IPV6_ND_TLL=33,/*Targetlink-layerforND.*/OFPXMT_OFB_MPLS_LABEL=34,/*MPLSlabel.*/OFPXMT_OFB_MPLS_TC=35,/*MPLSTC.*/OFPXMT_OFP_MPLS_BOS=36,/*MPLSBoSbit.*/OFPXMT_OFB_PBB_ISID=37,/*PBBI-SID.*/OFPXMT_OFB_TUNNEL_ID=38,/*LogicalPortMetadata.*/OFPXMT_OFB_IPV6_EXTHDR=39,/*IPv6ExtensionHeaderpseudo-field*/};交换机在它的流水线中必须支持表11中列出的required匹配域。每个required匹配域在交换机中必须至少有一个流表支持:流表必须保证匹配那个字段,匹配域的先决条件在表中必须已列出(见7.2.3.6)。required域并不需要在所有流表中实现,也不需要在相同流表中实现。流表可以支持no-requried和实验者匹配域。控制器可以查询交换机中每个流表支持哪些匹配域。每个匹配域有不同的大小,先决条件,和掩码能力,如表12所示。如果没有明确说明,每个字段类型指的就是数据包头域最外层事件。输入端口OXM_OF_IN_PORT是一个有效的标准openflow端口,可以是物理端口,逻辑端口,OFPP_LOCAL保留端口或是OFPP_CONTROLLER保留端口。物理端口OXM_OF_IN_PHY_PORT在包输入消息中用来标识逻辑端口下层的物理端口(见7.4.1)。在多个表间查找时,元数据域OXM_OF_METADATA用来传递信息。这个值可被随意覆盖。隧道ID字段OXM_OF_TUNNEL_ID携带与逻辑端口有关的可选元数据。元数据的映射由逻辑端口实现定义。如果逻辑端口不支持这样的数据或者数据包从物理端口接收,则值为0。例如,一个通过GRE隧道接收的数据包包括一个(32位)密钥,密钥存储在低32位,高32位为0。对MPLS逻辑端口,低20位表示MPLS标记。对VxLAN逻辑端口,低24位表示VNI。忽略OFPXMT_OFB_LAN_VID字段表明流表项应该匹配数据包,无论数据包是否包含相应的标签。对于VLAN标签定义了下列特殊值,允许其匹配任何标签的数据包,与标签的值无关,并且支持匹配没有VLAN标签的数据包。为OFPXMT_OFB_VLAN_VID定义的特殊值如下:/***/VLANid是12-bits,所以可以用总共16位来表示特殊情况enumofp_vlan_id{OFPVID_PRESENT=0x1000,/*表示VLANid的bit位*/OFPVID_NONE=0x0000,/*没有设置VLANid*/};当OFPXMT_OFB_VLAN_VID字段为通配时(不是当前)或者OFPXMT_OFB_VLAN_VID设置为OFPVID_NONE时必须拒绝OFPXMT_OFB_VLAN_PCP字段。表13总结了通配位的组合,以及特殊的VLAN标签匹配的域值。OXM_OF_IPV6_EXTHDR是一个伪字段,表明数据包头部中不同的IPV6扩展头部。IPV6扩展头部比特组合在OXM_OF_EXTHDR字段中,这些比特位有下列值:/*IPv6扩展报头定义位为pseudo-field*/enumofp_ipv6exthdr_flags{OFPIEH_NONEXT=1<<0,/*\"Nonextheader\"encountered.*/OFPIEH_ESP=1<<1,/*EncryptedSecPayloadheaderpresent.*/OFPIEH_AUTH=1<<2,/*Authenticationheaderpresent.*/OFPIEH_DEST=1<<3,/*1or2destheaderspresent.*/OFPIEH_FRAG=1<<4,/*Fragmentheaderpresent.*/OFPIEH_ROUTER=1<<5,/*Routerheaderpresent.*/OFPIEH_HOP=1<<6,/*Hop-by-hopheaderpresent.*/OFPIEH_UNREP=1<<7,/*Unexpectedrepeatsencountered.*/OFPIEH_UNSEQ=1<<8,/*Unexpectedsequencingencountered.*/};如果IPv6逐跳选项扩展报头作为数据包中第一个扩展报头则OFPIEH_HOP设为1。如果目前是一个IPv6路由扩展报头则设置OFPIEH_ROUTER为1。如果目前是IPv6分片扩展报头则设OFIEH_FRAG为1。如果目前是一个或多个IPv6目的地选项扩展报头则设OFPIEH_DEST为1。IPv6数据包中有一个或两个很正常(见RFC2460)。如果目前是IPv6身份验证扩展报头则设置OFPIEH_AUTH为1。如果目前是IPv6封装安全净荷扩展报头则设置OFPIEH_ESP为1。如果目前IPv6没有下一个头扩展报头怎设OFIEH_NONNEXT设为1。如果IPv6扩展报头不是RFC的优选项(不要求的),则设OFPIEH_UNSEQ为1。如果多个IPv6扩展报头不期而遇,则设OFPIEH_UNREP为1。(若是两个目的地的可选报头,将不需要设置该位)。7.2.3.8实验者流匹配字段对experimenter-specific流匹配字段的支持是可选的。Experimenter-specific可使用oxm_class=OFPXMC_EXPERIMENTER来定义流匹配字段。OXMTLVbody前4个字节包含实验者身份,结构体同ofp_experimenter(见7.5.4)。Oxm_field和OXMTLV其余部分都是experimenter-defined并且不需要填充或对齐。/*HeaderforOXMexperimentermatchfields.*/structofp_oxm_experimenter_header{uint32_toxm_header;/*oxm_class=OFPXMC_EXPERIMENTER*/uint32_texperimenter;/*ExperimenterIDwhichtakesthesameformasinstructofp_experimenter_header.*/};OFP_ASSERT(sizeof(structofp_oxm_experimenter_header)==8);7.2.4流指令结构体当流匹配了流表项,就执行与这个流表项相关的流指令。定义的指令列表如下:enumofp_instruction_type{OFPIT_GOTO_TABLE=1,/*Setupthenexttableinthelookuppipeline*/OFPIT_WRITE_METADATA=2,/*Setupthemetadatafieldforuselaterinpipeline*/OFPIT_WRITE_ACTIONS=3,/*Writetheaction(s)ontothedatapathactionset*/OFPIT_APPLY_ACTIONS=4,/*Appliestheaction(s)immediately*/OFPIT_CLEAR_ACTIONS=5,/*Clearsallactionsfromthedatapathactionset*/OFPIT_METER=6,/*Applymeter(ratelimiter)*/OFPIT_EXPERIMENTER=0xFFFF/*Experimenterinstruction*/};5.9节中介绍的指令集,流表可能支持指令类型的子集。指令定义包含指令类型,长度及相关数据。/*所有指令通用头部。长度包括头部和为了实现-bit对齐的填充部分。*NB:指令长度必须为8的倍数*/structofp_instruction{uint16_ttype;/*Instructiontype*/uint16_tlen;/*Lengthofthisstructinbytes.*/};OFP_ASSERT(sizeof(structofp_instruction)==4);OFPIT_GOTO_TABLE指令用以下结构体和字段:/*OFPIT_GOTO_TABLE的指令结构*/structofp_instruction_goto_table{uint16_ttype;/*OFPIT_GOTO_TABLE*/uint16_tlen;/*Lengthofthisstructinbytes.*/uint8_ttable_id;/*Setnexttableinthelookuppipeline*/uint8_tpad[3];/*Padtobits.*/};OFP_ASSERT(sizeof(structofp_instruction_goto_table)==8);table_id表示数据包处理流水线中的下一个表。OFPIT_WRITE_METADATA指令用以下结构和字段:/*OFPIT_WRITE_METADATA的指令结构*/structofp_instruction_write_metadata{uint16_ttype;/*OFPIT_WRITE_METADATA*/uint16_tlen;/*Lengthofthisstructinbytes.*/uint8_tpad[4];/*Alignto-bits*/uint_tmetadata;/*Metadatavaluetowrite*/uint_tmetadata_mask;/*Metadatawritebitmask*/};OFP_ASSERT(sizeof(structofp_instruction_write_metadata)==24);下一个表要查找元数据,可以用metadata和metadata_mask写入匹配字段的指定比特。如果这个指令没有规定,则元数据发送时不需改变。OFPIT_WRITE_ACTIONS,OFPIT_APPLY_ACTIONS,和OFPIT_CLEAR_ACTIONS指令用以下结构和字段:/*OFPIT_WRITE/APPLY/CLEAR_ACTIONS的结构体指令*/structofp_instruction_actions{uint16_ttype;/*OFPIT_*_ACTIONS的一种*/uint16_tlen;/*此结构体的比特长度*/uint8_tpad[4];/*位对齐*/structofp_action_headeractions[0];/*0个或多个与OFPIT_WRITE_ACTIONS和OFPIT_APPLY_ACTIONS相关的行动*/};OFP_ASSERT(sizeof(structofp_instruction_actions)==8);对于Apply-Actions指令,行动字段被当做一个列表,此行动应用于有序包。对于Write-Actions指令,行动字段作为一个集合,此行动并入当前行动集。对于Clear-Actions指令,此结构体不包含任何行动。指令OFPIT_METER使用以下的结构体和字段。/*OFPIT_METER的结构体指令*/structofp_instruction_meter{uint16_ttype;/*OFPIT_METER的类型*/uint16_tlen;/*Lengthis8.*/uint32_tmeter_id;/*Meter实例的ID.*/};OFP_ASSERT(sizeof(structofp_instruction_meter)==8);meter_id显示被应用在包上的测量。指令OFPIT_EXPERIMENTER使用以下的结构体和字段:/*OFPIT_EXPERIMENTER的结构体指令*/structofp_instruction_experimenter{uint16_ttype;/*OFPIT_EXPERIMENTER*/uint16_tlen;/*结构体的比特长度*/uint32_texperimenter;/*ExperimenterID,其格式同ofp_experimenter_header*//*实验者自定义的其它数据.*/};OFP_ASSERT(sizeof(structofp_instruction_experimenter)==8);7.2.5行动的结构许多行动是和流表项、组或数据相关的,目前定义的行动类型如下:Enumofp_action_type{OFPAT_OUTPUT=0/*输出到交换机端口*/OFPAT_COPY_TTL_OUT=11/*申请复制TTLoutwards去打包,从相邻外层到最外层*/OFPAT_COPY_TTL_IN=12/*申请复制TTLinwards打包,从最外层到相邻外层*/OFPAT_SET_MPLS_TTL=15,/*MPLSTTL*/OFPAT_DEC_MPLS_TTL=16,/*减少MPLSTTL*/OFPAT_PUSH_VLAN=17,/*压入一个新的VLAN标签OFPAT_POP_VLAN=18,/*弹出最外面的VLAN标签*/OFPAT_PUSH_MPLS=19,/*压入一个新的MPLS标签*/OFPAT_POP_MPLS=20,/*弹出最外面的MPLS标签*/OFPAT_SET_QUEUE=21,/*设置输出端口一个队列的ID*/OFPAT_GROUP=22,/*申请组*/OFPAT_SET_NW_TTL=23,/*IPTTL.*/OFPAT_DEC_NW_TTL=24,/*减少IPTTL.*/OFPAT_SET_FIELD=25,/*用OXMTLV格式设置一个头部字段*/OFPAT_PUSH_PBB=26,/*压入一个新的PBB服务标签(I-TAG)*/OFPAT_POP_PBB=27,/*弹出外面的PBB服务标签(I-TAG)*/OFPAT_EXPERIMENTER=0xffff};输出、组、建立队列的行动在5.12节进行了描述,压入/弹出的行动在表格6进行了介绍,表12用OXM类型对Set-Field的行动进行了描述,一个行动的定义包含了操作的类型、长度和任何关联的数据。/*行动的头部是所有行动共有的,长度包括它的头部和填充,使行动达到-bit。*NB:操作的长度必须是8的倍数,*/structofp_action_header{uint16_ttype;/*OFPAT_*之中的一个*/uint16_tlen;/*行动的长度,包括它的头部和填充,使行动达到-bit*/uint8_tpad[4];};OFP_ASSERT(sizeof(structofp_action_header)==8);一个输出行动是使用下面的结构和字段:/*OFPAT_OUTPUT是发送数据包到端口的行动结构。当‘port’是OFPP_CONTROLLER时,'max_len'表示发送的最大字节数。一个0的'max_len'表示没有字节需要被发送。一个OFPCML_NO_BUFFER的'max_len'表示数据包没有缓冲并且整个数据包将会被发送到控制器。structofp_action_output{uint16_ttype;/*OFPAT_OUTPUT.*/uint16_tlen;/*长度是16.*/uint32_tport;/*输出端口.*/uint16_tmax_len;/*发送给控制器的最大长度.*/uint8_tpad[6];/*填充到bits.*/};OFP_ASSERT(sizeof(structofp_action_output)==16);端口指的是数据包将发送的端口。max_len表示从OFPP_CONTROLLER端口发送出去的数据包中数据的最大值。如果max_len是0,这个交换机必须发送0字节。OFPCML_NO_BUFFER中的max_len表示整个数据包将发送,并且它不能缓冲。enumofp_controller_max_len{OFPCML_MAX=0xffe5,/*用来请求一个指定长度的max_len最大值*/OFPCML_NO_BUFFER=0xffff/*表明没有缓冲,整个数据包将会发送到控制器*/};Group行动使用下面的结构和字段:/*ActionstructureforOFPAT_GROUP.*/structofp_action_group{uint16_ttype;/*OFPAT_GROUP.*/uint16_tlen;/*长度是8.*/uint32_tgroup_id;/*数组标识符*/};OFP_ASSERT(sizeof(structofp_action_group)==8);group_id标识处理数据包的组,存储段集的使用依赖于组的类型。Set-Queue的行动设置队列id,用来映射一个流表项到已配置的端口队列,不考虑ToS和VLANPCP,这个数据包不会由于Set-Queue行动而发生改变。如果交换机内部处理需要设置ToS/PCP比特,那么在发送数据包之前应该恢复其原来的值。一个交换机可能只支持一个特定的PCP/ToS队列。在那种情况下,我们不能随意映射一个流表到那个特定的队列,因此Set-Queue行动不被支持。用户仍然可以使用这些队列,并通过设置有关字段(ToS,VLANPCP)等来映射流表项到队列。Set-Queue行动使用下面的结构和字段:/*OFPAT_SET_QUEUEactionstruct:发送数据包到端口的给定队列。*/structofp_action_set_queue{uint16_ttype;/*OFPAT_SET_QUEUE.*/uint16_tlen;/*Lenis8.*/uint32_tqueue_id;/*数据包的队列id.*/};OFP_ASSERT(sizeof(structofp_action_set_queue)==8);SetMPLSTTL行动使用下面的结构和字段:/*OFPAT_SET_MPLS_TTL的行动结构。*/structofp_action_mpls_ttl{uint16_ttype;/*OFPAT_SET_MPLS_TTL.*/uint16_tlen;/*长度是8.*/uint8_tmpls_ttl;/*MPLSTTL*/uint8_tpad[3];};OFP_ASSERT(sizeof(structofp_action_mpls_ttl)==8);mpls_ttl字段由MPLSTTL来设置。DecrementMPLSTTL行动无需协商而且只包含一个ofp_action_header,行动使MPLSTTL值减少。Set_IPv4TTL行动使用下列结构体和字段:/*ActionstructureforOFPAT_SET_NW_TTL.*/structofp_action_nw_ttl{uint16_ttype;/*OFPAT_SET_NW_TTL.*/uint16_tlen;/*Lengthis8.*/uint8_tnw_ttl;/*IPTTL*/uint8_tpad[3];};OFP_ASSERT(sizeof(structofp_action_nw_ttl)==8);nw_ttl字段是IP头部的TTL地址。DecrementIPv4TTL行动无需协商而且只包含一个ofp_action_header,行动使IP头部的TTL值减少。CopyTTLoutwards行动无需协商而且只包含一个ofp_action_header,行动从紧邻最外层的头部复制TTL值到最外层头部的TTL。CopyTTLinwards行动无需协商而且只包含一个ofp_action_header,行动从最外层的头部复制TTL值到紧邻最外层头部的TTL。PushVLANheader行动,PushMPLSheader和PushPBBheader行动使用下列结构体和字段:/*ActionstructureforOFPAT_PUSH_VLAN/MPLS/PBB.*/structofp_action_push{uint16_ttype;/*OFPAT_PUSH_VLAN/MPLS/PBB.*/uint16_tlen;/*Lengthis8.*/uint16_tethertype;/*Ethertype*/uint8_tpad[2];};OFP_ASSERT(sizeof(structofp_action_push)==8);ethertype表示Ethertype的新标签。当压入一个新的VLAN标签、新的MPLS头部或者PBB业务头部时会使用.PushPBBheader行动逻辑上会压入一个新的PBB业务实例头部到数据包(I-TAGTCI),并复制原始的数据包ethertype地址到标签的客户地址(C-DAandC-SA)。I-TAG的客户地址就封装在原始的Ethertype地址的位置上,因此这个操作可看作把骨干MAC-in-MAC头部和I-SID字段加到数据包前面。这个PushPBBheader行动不会把骨干VANL头部(B-TAG)加给数据包,它可在压入PBB头部操作之后再通过PushVlANheader的操作添加。这个操作之后,常规的set-field行动可用来修改外部Ethertype地址(B-DA和B-SA)。PopVLANheader行动不需要参数,仅由通用ofp_action_header组成,这个行动会弹出数据包最外面的VLAN标签。PopPBBheader行动不需要参数,仅由通用ofp_action_header组成。这个行动逻辑上会弹出数据包最外面的PBB业务实例头部,并且会复制数据包Ethernet地址里的客户地址。这个操作表示从数据包前面移走骨干MAC-in-MAC头部和I-SID字段。PopPBBheader行动不会移走数据包的骨干VLAN头部(B-TAG),它应在此操作之前通过PopVLANheader行动移走。PopMPLSheader的行动使用以下结构体和字段:/*行动结构forOFPAT_POP_MPLS.*/structofp_action_pop_mpls{uint16_ttype;/*OFPAT_POP_MPLS.*/uint16_tlen;/*长度是8.*/uint16_tethertype;/*ethertype*/uint8_tpad[2];};OFP_ASSERT(sizeof(structofp_action_pop_mpls)==8);ethertype表示MPLS负荷的Ethertype。不管“bottomofstack(BoS)\"比特是否在MPLS垫片上进行了设置,ethertype用来作为即将形成的数据包的Ethertype。推荐流表项使用这个行动来匹配MPLS标签和MPLSBoS字段来避免给MPLS负荷错误的ethertype。当BoS不等于1时,MPLS规范不允许对MPLS负荷设置任意的ethertype。控制器负责遵守这个要求,并且只能设置0x8847或0x8848作为那些MPLS负荷的ethertype。交换机可以随意的执行MPLS需求:此情况下,交换机应该拒绝任何与通配BoS相匹配的流表项,和在PopMPLSheader行动中,利用错误的ethertype匹配BoS为0的流表项。这两种情况都应该返回一个ofp_error_msg,带有OFPET_BAD_ACTION类型和OFPBAC_MATCH_INCONSISTENT代码.SetField行动使用以下结构体和行动:/*ActionstructureforOFPAT_SET_FIELD.*/structofp_action_set_field{uint16_ttype;/*OFPAT_SET_FIELD.*/uint16_tlen;/*长度会被填补到字节.*//*接着:*-精确的oxm_lenbytes包括一个单一OXMTLV,then*-Exactly((oxm_len+4)+7)/8*8-(oxm_len+4)(between0and7)*bytesofall-zerobytes*/uint8_tfield[4];/*OXMTLV-Makecompilerhappy*/};OFP_ASSERT(sizeof(structofp_action_set_field)==8);Field包含使用单一OXMTLV结构体的头部字段。Set-Field行动由oxm_type、OXMTLV类型、修改相应的数据包头部字段的值oxm_value以及OXM的负荷定义的。oxm_hasmask值必须是零而且不包括oxm_mask。流表项匹配必须包含设置的OXM有关字段(见7.2.3.6),否则将会生成一个错误(见6.4)。set-field行动的类型可以是任何有效的OXM头类型,7.2.3.7节和表12描述了可能的OXM类型。因为不是头部字段,不支持Set_Field行动的OXM类型OFPXMT_OFB_IN_PORT,OXM_OF_IN_PHY_PORT和OFPXMT_OFB_METADATA。Set-Field行动覆盖指定的OXM类型头部字段,并执行所需头部CRC计算。OXM字段是指头部最外层,除非字段类型明确指定其它字段,因此一般set-field行动适用于outermost-possible头(例如“SetVLANID“set-field行动总是设置最外层VLAN标签的ID)。一个实验者行动使用以下结构和字段:/*ActionheaderforOFPAT_EXPERIMENTER.*Therestofthebodyisexperimenter-defined.*/structofp_action_experimenter_header{uint16_ttype;/*OFPAT_EXPERIMENTER.*/uint16_tlen;/*长度是8的倍数.*/uint32_texperimenter;/*实验者ID与ofp_experimenter_header的结构相同*/};OFP_ASSERT(sizeof(structofp_action_experimenter_header)==8);Experimneter字段表示实验者ID,需要使用与ofp_experimenter相同的形式。7.3Controller-to-SwitchMessages7.3.1握手控制器使用OFPT_FEATURES_REQUEST消息识别交换机和读取它的基本功能。在会话建立(见6.3.1)基础上,控制器应该发送一个OFPT_FEATURES_REQUEST消息。这个消息只包含OpenFlow头部。交换机必须发送一个OFPT_FEATURES_REPLY响应消息:/*交换机功能*/structofp_switch_features{structofp_headerheader;uint_tdatapath_id;/*数据通路唯一的ID。低48-bits是MAC地址,高16位是开发者定义。*/uint32_tn_buffers;/*一次缓冲最大的数据包数。*/uint8_tn_tables;/*数据通路支持的表数量。*/uint8_tauxiliary_id;/*标识辅助连接/uint8_tpad[2];/*位对齐.*//*功能*/uint32_tcapabilities;/*位图的支持\"ofp_capabilities\".*/uint32_treserved;};OFP_ASSERT(sizeof(structofp_switch_features)==32);datapath_id唯一标识数据通路。低48位用于交换机MAC地址,高16位表示由开发者使用。一个例子就是使用高16位作为VLANID在一个物理交换机里区分多个虚拟交换机实例。这些字段应该被控制器视为一个不透明的位字符串。n_buffers字段表示交换机使用packet-in消息向控制器发送数据包时指定的最大缓冲数据包数量。n_tables字段描述交换机的表支持的数量,每一种表都可以对支持的匹配字段,行动和表项数量有不同的设置。当控制器和交换机第一次通信,控制器从特性回复中会发现有多少表交换机支持。如果它希望知道查询的表大小、类型和顺序,控制器发送一个OFPMP_TABLE_FEATURES复合请求(见7.3.5.5)。一个交换机必须按照数据包经过表的次序返回表。auxiliary_id字段表示交换机到控制器连接的类型,主连接这个字段的设置为零,辅助连接这个字段设置为非零值(见6.3.5)。Capabilities字段使用以下的组合标记:/*Capabilitiessupportedbythedatapath.*/enumofp_capabilities{OFPC_FLOW_STATS=1<<0,/*流量统计.*/OFPC_TABLE_STATS=1<<1,/*表统计.*/OFPC_PORT_STATS=1<<2,/*端口统计.*/OFPC_GROUP_STATS=1<<3,/*组统计.*/OFPC_IP_REASM=1<<5,/*可以重新组装IP碎片.*/OFPC_QUEUE_STATS=1<<6,/*队列统计.*/OFPC_PORT_BLOCKED=1<<8/*交换机将阻塞循环端口.*/};OFPC_PORT_BLOCKED位表示交换机协议,这在OpenFlow以外,如802.1D生成树,将检测拓扑环路并阻塞端口防止数据包循环。如果没有设置,在大多数情况下,控制器应该实现一个机制来防止数据包循环。7.3.2交换机配置控制器分别使用OFPT_SET_CONFIG和OFPT_GET_CONFIG_REQUEST消息可以设置和查询交换机配置参数。交换机对配置的要求做出回应OFPT_GET_CONFIG_REPLY消息;它没有对设置配置请求进行回复。OFPT_GET_CONFIG_REQUEST只有OpenFlow头部。OFPT_SET_CONFIG和OFPT_GET_CONFIG_REPLY使用以下结构:/*Switchconfiguration.*/structofp_switch_config{structofp_headerheader;uint16_tflags;/*OFPC_*flags位图.*/uint16_tmiss_send_len;/*数据通路应该发送给控制器的数据包最大字节数。见ofp_controller_max_len有效值*/};OFP_ASSERT(sizeof(structofp_switch_config)==12);配置标志包括以下:enumofp_config_flags{/*HandlingofIPfragments.*/OFPC_FRAG_NORMAL=0,/*分组没有特殊处理.*/OFPC_FRAG_DROP=1<<0,/*丢弃分组.*/OFPC_FRAG_REASM=1<<1,/*重新组装(只有OFPC_IP_REASM设置).*/OFPC_FRAG_MASK=3,};OFPC_FRAG_*标志表示IP分组是否应该正常处理、丢弃,或重组。“normal”处理分组意味着让分组穿过OpenFlow表。如果任何字段不存在(如TCP/UDP端口不合适),这个数据包应不匹配任何表项里已设置的字段。当不使用输出行动对OFPP_CONTROLLER逻辑端口时,miss_send_len字段定义了OpenFlow流水线发送到控制器的数据包字节数,例如,如果此消息被使能,则发送携带无效TTL的数据包。如果这个字段等于0,交换机必须发送ofp_packet_in消息中零字节长的数据包。如果该值设置为OFPCML_NO_BUFFER,消息中必须包含完整的包,而不会被缓冲。7.3.3FlowTableConfiguration流表编号从0和任意可取值直到OFPTT_MAX。OFPTT_ALL是一个保留值。/*表编号。表可以使用任何数值直至OFPT_MAX.*/enumofp_table{/*最后一个可用的表数.*/OFPTT_MAX=0xfe,/*假表.*/OFPTT_ALL=0xff/*通配符表用于表配置、流统计和删除.*/};控制器可以分别使用OFP_TABLE_MOD和OFPMP_TABLE请求对交换机配置和查询表状态。交换机使用OFPT_MULTIPART_REPLY消息响应表的复合请求。OFP_TABLE_MOD使用以下结构和字段:/*流表的配置/修改行为*/structofp_table_mod{structofp_headerheader;uint8_ttable_id;/*表的ID,OFPTT_ALL表示所有表*/uint8_tpad[3];/*填补到32字节*/uint32_tconfig;/*位图的OFPTC_*flags*/};OFP_ASSERT(sizeof(structofp_table_mod)==16);table_id表示配置更改时应选择的表。如果table_id是OFPTT_ALL,则配置应用于交换机中的所有表。Config字段是一个位图,早期版本的规范提供向后兼容性,保留以供将来使用。目前该定义的字段没有标记。该字段的值定义如下:/*配置表的标记,保留供将来使用.*/enumofp_table_config{OFPTC_DEPRECATED_MASK=3,/*废弃的比特*/};7.3.4ModifyStateMessages7.3.4.1ModifyFlowEntryMessage利用OFPT_FLOW_MOD消息控制器完成一个流表修改:/*流建立和拆除(controller->datapath).*/structofp_flow_mod{structofp_headerheader;uint_tcookie;/*不透明controller-issued标识符.*/uint_tcookie_mask;/*cookie位的掩码,当使用OFPFC_MODIFY*或OFPFC_DELETE*命令时必须匹配cookie。值为0表示没有*//*流行动*/uint8_ttable_id;/*放入流的表ID。对OFPFC_DELETE_*命令,OFPTT_ALL也可以用来删除所有表里匹配的流。*/uint8_tcommand;/*OFPFC_*之一.*/uint16_tidle_timeout;/*丢弃之前的空闲时间(seconds).*/uint16_thard_timeout;/*丢弃之前的最大时间(seconds).*/uint16_tpriority;/*流表项优先级.*/uint32_tbuffer_id;/*缓冲的包使用。或OFP_NO_BUFFER。对OFPFC_DELETE*则无意义*/uint32_tout_port;/*对于OFPFC_DELETE*命令,要求匹配的表项包含这个作为输出端口。OFPP_ANY表示没有*/uint32_tout_group;/*对于OFPFC_DELETE*命令,要求匹配的表项包括这个作为输出组。值OFPG_ANY表示没有。*/uint16_tflags;/*OFPFF_*的标记位图.*/uint8_tpad[2];structofp_matchmatch;/*字段相匹配,变量的大小.*//*变量的大小和填充匹配总是被指令跟着*///structofp_instructioninstructions[0];/*.*/};OFP_ASSERT(sizeof(structofp_flow_mod)==56);cookie字段是控制器选择的一个不透明的数据值。这个值出现在流删除消息和流统计,也可以用于过滤流统计,流修改和删除(见6.4)。数据包处理流水线不使用它,因此不需要驻留在硬件里。值-1(0xffffffffffffffff)保留,不得使用。当一个表项通过OFPFC_ADD消息插入流表中,其cookie字段设置为提供的值。当一个流表项修改(OFPFC_MODIFY或OFPFC_MODIFY_STRICT消息),其cookie字段不变。如果cookie_mask字段不为零,当修改或删除流表项时,和cookie字段一起流匹配。OFPFC_ADD消息忽略这个字段。cookie_mask字段的行动在6.4节说明。table_id字段表示哪个表中的流表项应插入、修改或删除。Table0表示流水线上第一个表。OFPTT_ALL只对删除请求有效。Command字段必须是下列之一:enumofp_flow_mod_command{OFPFC_ADD=0,OFPFC_MODIFY=1,OFPFC_MODIFY_STRICT=2,OFPFC_DELETE=3,OFPFC_DELETE_STRICT=4,}/*新流表.*//*修改所有匹配的流表.*//*修改严格匹配通配符和优先级的表项.*//*删除所有匹配的流动表*//*删除严格匹配通配符和优先级的表项.*/OFPFC_MODIFY和OFPFC_MODIFY_STRICT之间的区别在6.4节和解释,OFPFC_DELETE和OFPFC_DELETE_STRICT之间的区别在6.4节进行阐述。Idle_timeout和hard_timeout字段控制流表项过期的速度(见5.5)。当一个流表项插入表中,其idle_timeout和hard_timeout字段设置为消息中的值。当一个流表项修改(OFPFC_MODIFY或OFPFC_MODIFY_STRICT消息),idle_timeout和hard_timeout字段被忽略。如果设置了idle_timeout而hard_timeout为零,表项在idle_timeout秒后没有收到信息后必须过期。如果idle_timeout为零而设置了hard_timeout,无论是否有数据包正碰撞表项,表项到hard_timeout秒必须过期。如果idle_timeout和hard_timeout都设置了,流表项将在没有信息后idle_timeout秒,或hard_timeout秒后超时,以先到期者为准。如果idle_timeout和hard_timeout都是零,表项认为是永久的,不会超时。它可以被OFPFC_DELETE类型的flow_mod消息移除。Priority表示指定的流表中表的优先级。较高的数据表示较高的优先级。这一字段仅用于OFPFC_ADD消息匹配和添加流表项时,和当OFPFC_MODIFY_STRICT或OFPFC_DELETE_STRICT消息匹配流条目时。buffer_id指向交换机缓冲的数据包并用packet-in消息发送给控制器。如果没有缓冲数据包与flowmod关联,则必须设置为OFP_NO_BUFFER。在流插入后,包括一个有效buffer_id的flowmod移走缓冲区里对应数据包,并从第一个流表开始,穿过整个OpenFlow流水线进行处理。这实际上相当于发送了flowmod的一个双消息和packet-out转发到OFPP_TABLE逻辑端口(见7.3.7),同时要求交换机必须在数据包输出前完全处理flowmod。无论flowmod指向哪个表,或是flowmod中包含的指令都适用这些语法。OFPFC_DELETE和OFPFC_DELETE_STRICT消息忽略这一字段。输出端口和组利用out_port和out_group字段选择性的过滤OFPFC_DELETE和OFPFC_DELETE_STRICT消息。如果out_port或out_group包含一个分别大于OFPP_ANY或OFPG_ANY的值,就在匹配时引入了一个约束。这个约束就是对端口或组来说,流表项必须包含一个输出行动。其它约束如ofp_match结构和优先仍会使用;这纯粹是一个额外的约束。注意若禁用输出过滤,out_port和out_group必须分别设置为OFPP_ANY和OFPG_ANY。这些字段由OFPFC_ADD、OFPFC_MODIFY或OFPFC_MODIFY_STRICT消息忽略。Flags字段可能包含的下列标记:enumofp_flow_mod_flags{OFPFF_SEND_FLOW_REM=1<<0,/*发送删除消息当流过期或被删除.*/OFPFF_CHECK_OVERLAP=1<<1,/*首先要看的是重叠的表项.*/OFPFF_RESET_COUNTS=1<<2,/*重置流数据包和字节计数.*/OFPFF_NO_PKT_COUNTS=1<<3,/*不要监测的数据包计数.*/OFPFF_NO_BYT_COUNTS=1<<4,/*不要监测的字节计数.*/};OFPFF_SEND_FLOW_REM标志设置时,当流表项过期或删除时交换机必须发送一个流删除消息。OFPFF_CHECK_OVERLAP标志设置时,交换机在向流表中插入前,必须检查没有相同优先级的表项冲突。如果有的话,flowmod失败并返回一个错误信息(见6.4)。OFPFF_NO_PKT_COUNTS标志被设置时,交换机不需要监测流的数据包计数。OFPFF_NO_BYT_COUNTS标记被设置时,交换机不需要监测流的字节计数。设置这些标记可能减少一些OpenFlow交换机的处理负荷,尽管这些计数器在流表项删除消息和流统计时可能不可用。交换机不需要注意这些标记,可跟踪流计数并返回它不管相关标记的设置。如果一个交换机不跟踪流计数,相应的计数器不可用,它必须设置为字段最大值。当流表项插入到表中,它的flags字段设置为消息中的值。当一个流表项匹配和修改(OFPFC_MODIFY或OFPFC_MODIFY_STRICT消息),则flags字段被忽略。Instructions字段包含了流表项添加或修改表项的指令集。如果指令集是无效或不支持,交换机必须生成一个错误信息(见6.4)。7.3.4.2修改组表项消息控制器利用OFPT_GROUP_MOD消息对组表进行修改:/*组建立和拆除(controller->datapath).*/structofp_group_mod{structofp_headerheader;uint16_tcommand;/*OFPGC_*之一.*/uint8_ttype;/*OFPGT_*之一.*/uint8_tpad;/*填补到位.*/uint32_tgroup_id;/*组标识*/structofp_bucketbuckets[0];/*存储段数组的长度,从头部的长度字段计算*/};OFP_ASSERT(sizeof(structofp_group_mod)==16);语义类型和组字段解释6.5节。Command字段必须是下列之一:/*Groupcommands*/enumofp_group_mod_command{OFPGC_ADD=0,/*新建群组.*/OFPGC_MODIFY=1,/*修改所有匹配的组.*/OFPGC_DELETE=2,/*删除所有匹配的组。*/};Type字段必须是下列之一:/*组类型。值[128,255]保留给实验者使用.*/enumofp_group_type{OFPGT_ALL=0,/*所有的(多播/广播)组.*/OFPGT_SELECT=1,/*所选定组.*/OFPGT_INDIRECT=2,/*间接组*/OFPGT_FF=3,/*快速故障转移组.*/};group_id字段唯一地标识在交换机中的组。指定的组标识符定义如下:/*组编号。组可以使用任何不超过OFPG_MAX的编号。*/enumofp_group{/*最后一个可用的组号.*/OFPG_MAX=0xffffff00,/*假的组.*/OFPG_ALL=0xfffffffc,/*表示所有组的组删除命令.*/OFPG_ANY=0xffffffff/*通配符组仅用于流统计请求。选择所有流(包括没有组的流)*/};Buckets字段是一个存储段的数组。对间接组,数组必须包含一个存储段(见5.6.1),其它组类型在数组里可能有多个存储段。对快速故障转移组,存储段次序就定义了其优先级(见5.6.1),通过修改组可以改变存储段的排序(例如使用带OFPGC_MODIFY命令的OFPT_GROUP_MOD消息)。数组中的存储段使用以下结构:/*用于组的存储段*/structofp_bucket{uint16_tlen;/*存储段字节长度,包括头部和任何对齐位的填充.*/uint16_tweight;/*存储段的有关重量,为选择的组定义.*/uint32_twatch_port;/*状态会影响存储段是否活跃的端口。只需要快速转移故障的组。*/uint32_twatch_group;/*状态会影响存储段是否活跃的组。只需要快速转移故障的组。*/uint8_tpad[4];structofp_action_headeractions[0];/*与存储段关联的0或多个行为,行动列表长度依据存储段长度计算*/};OFP_ASSERT(sizeof(structofp_bucket)==16);Weight字段只是为所选组定义的,它是否支持是可选的。被组处理的存储段共享信息由组中存储段重量之和平均后的单个存储段重量来定义。当一个端口拆除,信息量分布的改变没有定义,交换机的数据包分布精确度应与存储段重量匹配,但没有定义。watch_port和watch_group字段只有快速故障转移组需要,也可能选来实现用在其它组类型上。这些字段表示端口或组,其活跃控制这个存储段是否为转发的候选者。对快速转移故障组,定义的第一个存储段是最高优先级,而且只有最高优先级活跃存储段被使用(见5.6.1)。actions字段是与存储段相关的行动集。当存储段被数据包选中时,其行动集就应用到数据包(见5.10)。7.3.4.3PortModificationMessage控制器使用OFPT_PORT_MOD消息修改端口的行为:/*物理端口的修改行为*/structofp_port_mod{structofp_headerheader;uint32_tport_no;uint8_tpad[4];uint8_thw_addr[OFP_ETH_ALEN];/*这是不可配置的硬件地址。这是用来对请求进行正常检查,因此它必须返回相同ofp_port结构.*/uint8_tpad2[2];/*填充到字节.*/uint32_tconfig;/*OFPPC_*位图标记.*/uint32_tmask;/*位图OFPPC_*标记的改变.*/uint32_tadvertise;/*位图的OFPPF_*。所有位为零以防止任何行动发生.*/uint8_tpad3[4];/*填充到字节.*/};OFP_ASSERT(sizeof(structofp_port_mod)==40);Mask字段用来在config字段中选择比特去改变。Advertise字段没有掩码;所有端口特性一起改变。7.3.4.4计量器修改消息利用OFPT_METER_MOD消息完成控制器的计量器修改:/*计量器配置.OFPT_METER_MOD.*/structofp_meter_mod{structofp_headerheader;uint16_tcommand;/*OFPMC_*之一.*/uint16_tflags;/*OFPMF_*位图的标记.*/uint32_tmeter_id;/*计量器实例.*/structofp_meter_band_headerbands[0];/*带宽列表长度,从头度字段计算.*/};OFP_ASSERT(sizeof(structofp_meter_mod)==16);meter_id字段在交换机里唯一地标识计量器。计量器从meter_id=1开始定义,直至交换机可以支持的最大数。OpenFlow协议还定义了一些额外的不与流表相关的虚拟计量器:/*计量器编号。OFPM_MAX流表计可以使用任何数直至OFPM_MAX*/enumofp_meter{/*最后一个可用的计量器.*/OFPM_MAX=0xffff0000,/*虚拟仪表.*/OFPM_SLOWPATH=0xfffffffd,/*用于慢速数据通道的计量器.*/OFPM_CONTROLLER=0xfffffffe,/*用于控制器连接的计量器。*/OFPM_ALL=0xffffffff,/*表示用于统计请求命令的所有计量器*/};OpenFlow现有实现提供支持的虚拟计量器,在新实现中鼓励使用常规流计量器或优先级队列。OFPM_CONTROLLER:虚拟计量器使用CONTROLLER保留端口或其他处理,控制所有数据包通过Packet-inmes-sages发送到控制器,(见6.1.2)。可用来发送到控制器的流量。OFPM_SLOWPATH:虚拟计量器控制所有数据包被缓慢数据通路的交换机处理。许多交换机实现有一条快和慢数据通路,例如硬件交换机可能有一条慢速软数据通路,或软交换机可能有一条慢速的用户空间数据通道。Command字段的命令必须是下列之一:/*Metercommands*/enumofp_meter_mod_command{OFPMC_ADD,/*新的计量器.*/OFPMC_MODIFY,/*修改指定的计量器.*/OFPMC_DELETE,/*删除指定的计量器.*/};Flags字段可能包含以下标记的组合:/*计量器配置标记*/enumofp_meter_flags{OFPMF_KBPS=1<<0,/*速率值在kb/s(kilo-bit每秒.*/OFPMF_PKTPS=1<<1,/*速率值用包/秒记.*/OFPMF_BURST=1<<2,/*突发的尺寸.*/OFPMF_STATS=1<<3,/*收集统计.*/};Bands字段是一个速率带宽列表。它可以包含任意数量的频带,当可以理解的话,每个频带类型是可以重复的。一次只能使用一个频带,如果当前数据包速度超过多个频带速率,频带则用最高的速率配置。所有的频带都使用相同的通用头部来定义:/*所有计量器共同的头部*/structofp_meter_band_header{uint16_ttype;/*OFPMBT_*.之一*/uint16_tlen;/*此频带的字节长度.*/uint32_trate;/*此频带的速率.*/uint32_tburst_size;/*突发的的大小*/};OFP_ASSERT(sizeof(structofp_meter_band_header)==12);Rate字段表示速率值,在此频带基础上可以传送数据包(见5.7.1)。速率值单位是千比特/秒,除非flags字段包括OFPMF_PKTPS,此时速率是包/秒。burst_size字段只有在flags字段包含OFPMF_BURST时使用。对所有长度超过突发值的数据包和突发字节,它规定了计量器的粒度,计量器的速率将严格。突发值单位是千比特,除非flags字段包括OFPMF_PKTPS,在这种情况下,突发值单位是包。Type字段必须是下列之一:/*计量器频带类型*/enumofp_meter_band_type{OFPMBT_DROP=1,/*丢弃包.*/OFPMBT_DSCP_REMARK=2,/*IP头部的DSCP.*/OFPMBT_EXPERIMENTER=0xFFFF/*实验者计量器频带.*/};OpenFlow交换机可能不支持所有频带类型,并可能不允许在所有计量器上使用它所支持的频带,即一些计量器可能是专用的。频带OFPMBT_DROP定义了简单的速率器,超过频带速率值的话数据包将丢弃,并使用以下结构:/*OFPMBT_DROPband-droppackets*/structofp_meter_band_drop{uint16_ttype;/*OFPMBT_DROP.*/uint16_tlen;/*这个频带的字节长度.*/uint32_trate;/*开始丢弃包的速率*/uint32_tburst_size;/*突发大小*/uint8_tpad[4];};OFP_ASSERT(sizeof(structofp_meter_band_drop)==16);频带OFPMBT_DSCP_REMARK定义了一个简单的DiffServ策略,对超过频带速率的数据包的IP头部DSCP字段,检测其丢弃的优先级,并使用以下结构:/*OFPMBT_DSCP_REMARK频带-IP头部DSCP*/structofp_meter_band_dscp_remark{uint16_ttype;/*OFPMBT_DSCP_REMARK.*/uint16_tlen;/*频带的字节长度.*/uint32_trate;/*开始检测数据包的速率.*/uint32_tburst_size;/*突发大小*/uint8_tprec_level;/*添加的丢弃优先级数。*/uint8_tpad[3];};OFP_ASSERT(sizeof(structofp_meter_band_dscp_remark)==16);prec_level字段表示如果超过频带速率超过某个数值,数据包的丢弃优先级应该增加。频带OFPMBT_EXPERIMENTER是实验者定义并使用以下结构:/*OFPMBT_EXPERIMENTER频带-行动集中的写行动*/structofp_meter_band_experimenter{uint16_ttype;/*OFPMBT_*之一.*/uint16_tlen;/*这个频带的字节长度.*/uint32_trate;/*这个频带的速率*/uint32_tburst_size;/*突发大小.*/uint32_texperimenter;/*实验者ID与ofp_experimenter_header结构相同*/};OFP_ASSERT(sizeof(structofp_meter_band_experimenter)==16);7.3.5复合消息复合消息用于编码请求或应答那些可能携带大量数据而且不能装进单个OpenFlow消息(仅限于kb)的情况。请求或应答是编码序列与特定的多部分类型的多部分消息,并佐的接收器。多部分消息主要用于请求数据或从交换机状态信息。请求被放在一个或多个OFPT_MULTIPART_REQUEST消息:structofp_multipart_request{structofp_headerheader;uint16_ttype;/*OFPMP_*之一.*/uint16_tflags;/*OFPMPF_REQ_*标记.*/uint8_tpad[4];uint8_tbody[0];/*请求的body。0或多个字节.*/};OFP_ASSERT(sizeof(structofp_multipart_request)==16);enumofp_multipart_request_flags{OFPMPF_REQ_MORE=1<<0/*更多的请求跟随.*/};交换机用一个或多个OFPT_MULTIPART_REPLY消息进行响应:structofp_multipart_reply{

structofp_headerheader;uint16_ttype;/*一个OFPMP_*常数.*/uint16_tflags;/*OFPMPF_REPLY_*标记.*/uint8_tpad[4];uint8_tbody[0];/*回答的body,0或更多字节.*/};OFP_ASSERT(sizeof(structofp_multipart_reply)==16);enumofp_multipart_reply_flags{OFPMPF_REPLY_MORE=1<<0/*更多回复跟随*/};在请求和回复中为flags定义的值是唯一的,是否更多的请求/回复会跟随这个——这个值就是0x0001。为了方便实现,控制器允许发送请求和交换机允许发送回复时不携带额外的表项(即一个空的body)。然而,另一个消息必须使用更多的标志设置去跟随一个消息。跨越多个消息(有一个或多个消息设置了更多的标志)的请求或应答,消息队列中的所有消息必须使用相同的复合类型和事务id(xid)。如果多个未回答的复合请求或回复同时在传输中,复合请求或应答的消息可能与其他OpenFlow消息类型交替,包括其他复合请求或回复,但必须有不同的事务id。回复的事务id必须匹配激起他们的请求。在请求和响应中,type字段指所传递信息的种类,并决定如何解析body字段:enumofp_multipart_type{/*描述这个OpenFlow交换机。*请求body是空的。*回复主体是structofp_desc.*/OFPMP_DESC=0,/*单独流统计。*请求body是ofp_flow_stats_request结构。*回复body是一个structofp_flow_stats数组。.*/OFPMP_FLOW=1,/*总的流统计。*请求body是ofp_aggregate_stats_request结构。*回复body是ofp_aggregate_stats_reply结构.*/OFPMP_AGGREGATE=2,/*流表统计。*请求body是空的。*回复body是ofp_table_stats结构数组。*/OFPMP_TABLE=3,/*端口统计。*请求body是ofp_port_stats_request结构。*回复body是ofp_port_stats结构数组。*/OFPMP_PORT_STATS=4,/*一个端口的队列统计*请求的body是ofp_queue_stats_request结构体.*回复body是ofp_queue_stats结构体数组*/OFPMP_QUEUE=5,/*组计数器统计。*请求的body是ofp_group_stats_request结构体.*回复是ofp_group_stats结构体数组*/OFPMP_GROUP=6,/*组描述。*请求body是空的。/*回复body是ofp_group_desc结构体数组*/OFPMP_GROUP_DESC=7,/*组特征。*请求body为空。*回复body是ofp_group_features结构体。*/OFPMP_GROUP_FEATURES=8,/*计量器统计*请求body是ofp_meter_multipart_requests结构体。*回复body是ofp_meter_stats结构体数组*/OFPMP_METER=9,/*计量器配置*请求body是ofp_meter_multipart_requests结构体.*回复body是ofp_meter_config结构体数组。*/OFPMP_METER_CONFIG==10,/*计量器特征*请求body为空。*回复body是ofp_meter_features结构体。*/OFPMP_METER_FEATURES=11,/*表特征*请求body是空的或包含ofp_table_features结构体数组,包含控制器所需的交换机视图。如果交换机不能设置特定的视图,就会返回一个error.*回复body是一组ofp_table_features结构体.*/OFPMP_TABLE_FEATURES=12,/*端口说明*请求body是空的。*回复body是ofp_port结构体数组*/OFPMP_PORT_DESC=13,/*实验者扩展项*请求body和回复body都以ofp_experimenter_multipart_header结构体开始。*而请求body和回复body是由实验者定义的。*/OFPMP_EXPERIMENTER=0xffff};如果一个复合请求跨越多个消息并且扩展到交换机不能缓冲的大小,那么交换机必须回复一个OFPET_BAD_REQUEST类型的错误消息并且编码为OFPBRC_MULTIPART_BUFFER_OVERFLOW。如果一个复合请求包含一个不支持的类型,交换机必须回复一个OFPET_BAD_REQUEST类型的错误消息并且编码为OFPBRC_BAD_MUTIPART.在所有包含统计数字复合应答中,如果在交换机中没有指定的数字计数器,其值必须被设置为字段最大值(无符号数=-1)。计数器是无符号的并且循环时无溢出指示。7.3.5.1说明关于交换机厂商、硬件修订、软件修订、序列号和描述字段的信息,可以从OFPMP_DESCmultipart请求类型中获得:/*OFPMP_DESC请求的回复部分。每个表项都是NULL结束的ASCII码字符串*/structofp_desc{charmfr_desc[DESC_STR_LEN];/*厂商说明.*/charhw_desc[DESC_STR_LEN];/*硬件说明.*/charsw_desc[DESC_STR_LEN];/*软件说明.*/charserial_num[SERIAL_NUM_LEN];/*序列号.*/chardp_desc[DESC_STR_LEN];/*可读的数据通道描述.*/};OFP_ASSERT(sizeof(structofp_desc)==1056);每个表项都是ASCII码格式并且用空字节(\\0)从右边填充。DESC_STR_LEN是256,SERIAL_NUM_LEN是32。dp_desc是一个自由形式的字符串,调试时用来描述数据通道,例如:“switch3inroom3120”。因此,它不能被保证是唯一的并且不应用作数据通道的主要标识—-使用交换机的datapath_id字段来代替。7.3.5.2单个的流统计关于单个流表项的信息使用OFPMP_FLOW复合请求类型进行请求:/*OFPMP_FLOW的ofp_multipart_request部分*/structofp_flow_stats_request{uint8_ttable_id;/*要读的table_ID(fromofp_table_stats),OFPTT_ALL表示所有表.*/uint8_tpad[3];uint32_tout_port;uint32_tout_group;uint8_tpad2[4];uint_tcookie;uint_tcookie_mask;Structofp_matchmatch;};OFP_ASSERT(sizeof(structofp_flow_stats_request)==40);/*对齐到32bits.*//*作为一个输出端口要求包含这个匹配项.一个OFPP_ANY值表示没有。*//*作为一个输出组要求包含这个匹配项,一个OFPG_ANY值表示没有*//*对齐到bits.*//*要求匹配项要包含这个cookie值。*//*掩码用来那些必须匹配的cookiebits.0表示没有*//*用来匹配的字段,可变大小*/匹配字段包含需匹配的流表项说明,还可含有通配符和掩码字段。这些字段的匹配行为在6.4中介绍。Table_id表示一个将读取的一个流表的索引值,OFPTT_ALL表示所有流表。Out_port和out_group字段可又输出端口和组选择过滤。如果out_port或out_group包含一个分别不同于OFPP_ANY和OFPG_ANY的值,它会在匹配的时候引进一个约束。这个约束就是流表项必须包含一个指定端口或组的输出行动。其它约束例如ofp_match结构仍然在使用;这是纯粹一个额外的约束。注意为了禁止输出过滤,out_port和out_group都必须分别设置为OFPP_ANY和OFPG_ANY。Cookie和cookie_mask字段的用法见6.4部分。回复一个OFPMP_FLOW复合请求的部分由下列队列组成:/*回复一个OFPMP_FLOW请求的部分。*/structofp_flow_stats{uint16_tlength;/*这个项的长度*/uint8_ttable_id;/*流的来源表ID*/uint8_tpad;uint32_tduration_sec;/*流已生成的时间,以秒记*/uint32_tduration_nsec;/*流存在的时间超过duration_sec的时间,以ns记*/uint16_tpriority;/*流表项的优先权*/uint16_tidle_timeout;/*在到期之前闲置的秒数*/uint16_thard_timeout;/*到期之前的秒数*/uint16_tflags;/*OFPFF_*flags位图.*/uint8_tpad2[4];/*对齐到-bits.*/uint_tcookie;/*控制器发出的不透明标识符*/uint_tpacket_count;/*流里的包的数目。*/uint_tbyte_count;/*流的字节数.*/structofp_matchmatch;/*字段说明.可变大小*//*可变大小和填充的匹配总是跟随着指令.*///structofp_instructioninstructions[0];/*指令集--0或者更多.*/};OFP_ASSERT(sizeof(structofp_flow_stats)==56);由创建流表项的flow_mod提供的字段(见7.3.4.1),加上插入到流表项中的table_id,packet_count和byte_count对所有被流表项处理的数据包进行计数。duration_nsec和duration_sec字段显示流表项安装在交换机中已过去的时间。总共持续的时间可用duration_sec*10^9+duration_nsec计算出。实现的话要求提供第二精度;在能够获得的情况下鼓励用更高的精度。7.3.5.3总计的流统计关于多个的流表项的总计信息用OFPMP_AGGREGATE复合请求类型来请求:/*OFPMP_AGGREGATE类型的ofp_aggregate_atats_request部分*/structofp_aggregate_stats_request{uint8_ttable_id;/*要读取的表ID(来自ofp_table_stats),OFPTT_ALL为所有的表*/uint8_tpad[3];/*排列到32bits.*/uint32_tout_port;/*包含此项匹配的流表项要求作为一个输出端口.OFPP_ANY值表示没有*/uint32_tout_group;/*包含此项匹配的流表项要求作为一个输出组,OFPG_ANY值表示没有*/uint8_tpad2[4];/*排列到bits.*/uint_tcookie;/*要求正在匹配的流表项去包含这些cookie值*/uint_tcookie_mask;/*掩码(mask)用来那些必须匹配的cookie比特,0表示没有.*/structofp_matchmatch;/*将匹配的字段.可变大小.*/};OFP_ASSERT(sizeof(structofp_aggregate_stats_request)==40);在这个消息的中的字段与在单独的流统计请求(OFPMP_FLOW)里有相同的含义。回复部分的组成如下:/*OFPMP_AGGREGATE请求的回复部分.*/structofp_aggregate_stats_reply{uint_tpacket_count;/*流中的数据包数.*/uint_tbyte_count;/*流中的字节数.*/uint32_tflow_count;/*流的数目.*/uint8_tpad[4];/*排列到bits.*/};OFP_ASSERT(sizeof(structofp_aggregate_stats_reply)==24);7.3.5.4表统计请求关于表的信息使用OFPMP_TABLE复合请求类型。在请求内不包含任何数据。回复部分由如下一个数组组成:/*回复给OFPMP_TABLE请求的部分.*/structofp_table_stats{uint8_ttable_id;/*表标识符.低数值的表第一个访问*/uint8_tpad[3];/*排列到32-bits.*/uint32_tactive_count;/*活跃的流表项数量.*/uint_tlookup_count;/*表中处理过的数据包数量.*/uint_tmatched_count;/*表中匹配的数据包数量。*/};OFP_ASSERT(sizeof(structofp_table_stats)==24);在交换机支持的每一个表中,数组都有一个结构。流表项是以数据包通过表的顺序返回的。7.3.5.5表特征OFPMP_TABLE_FEATURES复合类型允许一个控制器去查询现存的表的能力和选择要求交换机去重新配置表去匹配一个已有的配置。一般来讲,表的能力体现了一个表的所有可能的特征,然而一些能力互不兼容,目前的能力结构不允许我们去解决兼容问题。7.3.5..5.1表特征请求和回复如果OFPMP_TABLE_FEATURES请求是空的,交换机将返回一组包含当前配置流表能力的ofp_table_features结构体。如果请求部分包含一个或更多ofp_table_features结构体的队列,交换机将尝试去改变它的流表去匹配被请求的流表配置。这个操作配置整个流水线,流水线里的流表设置必须和请求的设置匹配,否则必须返回一个error。尤其是,如果这个配置成功进行了设置,则给一个或更多交换机支持的流表的请求结构若不包含一个ofp_table_features结构体,这些流表将从流水线中被移除。配置改变成功会修改请求里面的所有流表的特性,也就是说,要么在请求里被指定的所有流表都修改,要么一个都不改,并且新的流表的功能必须是超集或者和被请求的功能相同。如果流表配置成功了,已删除的流表或在新旧配置里能力改变的流表,其流表项都将从流表中删除。如果交换机不能设置所请求的配置,将返回一个OFPET_TABLE_FEATURES_FAILED类型错误并带有适当错误代码。含有ofp_table_features的请求和回复至少要满足以下要求:●每个ofp_table_features结构的table_id字段的值在消息所有的ofp_table_features结构里应该是唯一的。●每个ofp_table_features结构的属性字段必须包含一个ofp_table_feature_prop_type属性,以及另外两个。第一,the_MISS后缀可能被忽略,如果它和常规流表项相应的属性相同;第二,OFPTFPT_EXPERIMENTER和OFPTFPT_EXPRIMENTER_MISS类型的属性可能会被多次忽略或使用。排序未规定,但鼓励使用在规范上列出的次序。(见7.3.5.5.2)一个交换机接收到一个请求,若不满足所需请求,应该返回一个OFPET_TABLE_FEATURES_FALLED类型的错误并带有适当的代码。下面的结构说明表特性请求和回复的部分:/*OFPMP_TABLE_FEATURES类的ofp_multipart_request部分.//*回复OFPMP_TABLE_FEATURES请求的部分.*/structofp_table_features{uint16_tlength;/*长度被填至bits.*/uint8_ttable_id;/*表的标识符.低编号先询问.*/uint8_tpad[5];/*排到-bits.*/charname[OFP_MAX_TABLE_NAME_LEN];uint_tmetadata_match;/*表能匹配元数据的位数.*/uint_tmetadata_write;/*表能写的元数据位数.*/uint32_tconfig;/*OFPTC_*值的位图*/uint32_tmax_entries;/*流表项被支持的最大数.*//*表特征属性列举*/structofp_table_feature_prop_headerproperties[0];/*属性举例*/};OFP_ASSERT(sizeof(structofp_table_features)==);数组有一个结构给每个被交换机支持的流表。流表项总是按照数据表通过流表的顺序返回。OFP_MAX_TABLLE_NAME_LEN是32。该metadata_match字段表示流表利用ofp_match结构体元数据字段时可匹配的元数据字段的位数,。值0xFFFFFFFFFFFFFFFF表明表可以匹配整个元数据字段。该metadata_write字段显示表可以使用ofpit_write_metadata指令写元数据字段的位数。值0xFFFFFFFFFFFFFFFF表明表可以写整个元数据字段。配置字段是表的配置,通过表的配置信息对表进行设置(见7.3.3)Max_entries字段表示能插入表的流表项最大数量。由于现代的硬件的,该max_entries值应考虑建议值和接近表最大努力的性能。不考虑表的高层抽象,在实践中通过一个单一的流表项所消耗的资源是不固定的。例如,一个流表项可能消耗多个流表项的资源,取决于它的匹配参数(e.g.IPv4vs.IPv6)。而且,在同个OPENFLOW层不同的表可能实际上共享相同的底层物理资源。进一步说,基于OpenFlow混合交换机,这些表可能与非OpenFlow功能部分共享。结果是交换机实现者应该报告所支持的总的流表项值,并且控制器的作者不应该把这个值设为固定的,物理常数。properties字段是表特征属性的一个列表,描叙表的不同性能。7.3.5.5.2表特征属性目前定义的表特征属性类型的清单是:/*表特征属性类型.*最低位被清除表示一个常规流表项的一个属性.*最低位被设置表示Table-MissFlowEntry的一个属性.*/enumofp_table_feature_prop_type{OFPTFPT_INSTRUCTIONS=0,/*指令属性.*/OFPTFPT_INSTRUCTIONS_MISS=1,/*table-miss的指令.*/OFPTFPT_NEXT_TABLES=2,/*NextTable属性.*/OFPTFPT_NEXT_TABLES_MISS=3,/*NextTablefortable-miss.*/OFPTFPT_WRITE_ACTIONS=4,/*WriteActions属性.*/OFPTFPT_WRITE_ACTIONS_MISS=5,/*WriteActionsfortable-miss.*/OFPTFPT_APPLY_ACTIONS=6,/*ApplyActions属性.*/OFPTFPT_APPLY_ACTIONS_MISS=7,/*ApplyActionsfortable-miss.*/OFPTFPT_MATCH=8,/*匹配属性.*/OFPTFPT_WILDCARDS=10,/*Wildcards属性.*/OFPTFPT_WRITE_SETFIELD=12,/*WriteSet-Field属性.*/OFPTFPT_WRITE_SETFIELD_MISS=13,/*WriteSet-Fieldfortable-miss.*/OFPTFPT_APPLY_SETFIELD=14,/*ApplySet-Field属性.*/OFPTFPT_APPLY_SETFIELD_MISS=15,/*ApplySet-Fieldfortable-miss.*/OFPTFPT_EXPERIMENTER=0xFFFE,/*Experimenter属性.*/OFPTFPT_EXPERIMENTER_MISS=0xFFFF,/*Experimenterfortable-miss.*/};_MISS后缀的属性描述漏表流表项的功能(见5.4),而其他属性描述常规流表项的功能。如果一个指定属性没有任何功能(例如不支持Set_Field),一个空列表属性也必须被包含在属性列表里。当漏表流表项的一个属性和常规流表项相应的属性相同,(i.e.两个属性都有相同的功能清单),这个漏表属性可以从属性列表里清除。一个属性定义包含属性类型、长度和关联的数据:/*所有表特征属性常用的标头*/structofp_table_feature_prop_header{uint16_ttype;/*OFPTFPT_*中之一.*/uint16_tlength;/*这个属性占字节长度.*/};OFP_ASSERT(sizeof(structofp_table_feature_prop_header)==4);OFPTFPT_INSTRUCTIONS和OFPTFPT_INSTRUCTIONS_MISS属性使用如下结构和字段:/*指令属性*/structofp_table_feature_prop_instructions{uint16_ttype;/*OFPTFPT_INSTRUCTIONS和OFPTFPT_INSTRUCTIONS_MISS之一.*/uint16_tlength;/*这个属性的字节长度.*//*接下来是:*-准确地讲(length-4)个字节包含指令的id,其次*-精确地(length+7)/8*8-(length)(between0and7)*全零字节的字节数*/structofp_instructioninstruction_ids[0];/*指令列表*/};OFP_ASSERT(sizeof(structofp_table_feature_prop_instructions)==4);Instruction_ids是被这个表支持的指令列表(见5.9)。列表里的元素是可变大小的,用于实验者表述指令的,非实验者指令是4字节。OFPTFPT_NEXT_TABLES和OFPTFPT_NEXT_TABLES_MISS属性使用如下结构和字段:/*NextTables属性*/structofp_table_feature_prop_next_tables{uint16_ttype;/*OFPTFPT_NEXT_TABLES和OFPTFPT_NEXT_TABLES_MISS之一.*/uint16_tlength;/*这个属性占的字节长度.*//*Followedby:*-Exactly(length-4)bytescontainingthetable_ids,then*-Exactly(length+7)/8*8-(length)(between0and7)*bytesofall-zerobytes*/uint8_tnext_table_ids[0];/*表地址列表.*/};OFP_ASSERT(sizeof(structofp_table_feature_prop_next_tables)==4);next_table_ids是表的数组,使用该OFPIT_GOTO_TABLE指令可以直接到达本表。(见5.1)。OFPTFPT_WRITE_ACTIONS,OFPTFPT_WRITE_ACTIONS_MISS,OFPTFPT_APPLY_ACTIONS和OFPTFPT_APPLY_ACTIONS_MISS属性使用如下结构和字段:/*行动属性*/structofp_table_feature_prop_actions{uint16_ttype;/*OFPTFPT_WRITE_ACTIONS,OFPTFPT_WRITE_ACTIONS_MISS,OFPTFPT_APPLY_ACTIONS,FPTFPT_APPLY_ACTIONS_MISS.中之一*/uint16_tlength;/*该属性字节长度.*//*Followedby:*-Exactly(length-4)bytescontainingtheaction_ids,then*-Exactly(length+7)/8*8-(length)(between0and7)*bytesofall-zerobytes*/structofp_action_headeraction_ids[0];/*Listofactions*/};OFP_ASSERT(sizeof(structofp_table_feature_prop_actions)==4);Action_ids是特征的行动列表(见5.12)。列表里的元素是可变大小的,用于实验者表述指令,非实验者指令是4字节。OFPTFPT_WRITE_ACTIONS和OFPTFPT_WRITE_ACTIONS_MISS属性描述使用OFPIT_WRITE_ACTIONS指令的表所支持的行动,而OFPTFPT_APPLY_ACTIONS和OFPTFPT_APPLY_ACTIONS_MISS属性描述被正在使用OFPIT_APPLY_ACTIONS指令的表支持的行动。OFPTFPT_MATCH,OFPTFPT_WILDCARDS,OFPTFPT_WRITE_SETFIELD,OFPTFPT_WRITE_SETFIELD_MISS,OFPTFPT_APPLY_SETFIELD和OFPTFPT_APPLY_SETFIELD_MISS属性使用如下结构和字段:/*Match,Wildcard或Set-Field属性*/structofp_table_feature_prop_oxm{uint16_ttype;/*OFPTFPT_MATCH,OFPTFPT_WILDCARDS,OFPTFPT_WRITE_SETFIELD,OFPTFPT_WRITE_SETFIELD_MISS,OFPTFPT_APPLY_SETFIELD,OFPTFPT_APPLY_SETFIELD_MISS.中之一*/uint16_tlength;/*Lengthinbytesofthisproperty.*//*Followedby:*-Exactly(length-4)bytescontainingtheoxm_ids,then*-Exactly(length+7)/8*8-(length)(between0and7)*bytesofall-zerobytes*/uint32_toxm_ids[0];/*OXM头数组*/};OFP_ASSERT(sizeof(structofp_table_feature_prop_oxm)==4);oxm_ids是针对特征的OXM类型列表(见7.2.3.2)。列表里是32位OXM头或者实验者使用的位OXM头。OFPTFPT_MATCH属性表示特别的表所支持匹配的字段(见7.2.3.7)。例如:如果表能够匹配入端口,一个OXM_OF_IN_PORT类型的OXM头应该被包括在列表里。如果在OXM头中HASMASK位被设置,那么交换机必须支持为所给的掩码类型。OFPTFPT_WILDCARDS属性表示特别的表所支持通配(省略)的字段。例如,一个直接查找的哈希表将把列表变空,而一个TCAM表或者有序查询表将设置成和OFPTFPT_MATCH属性相同的值。OFPTFPT_WRITE_SETFIELD和OFPTFPT_WRITE_SETFIELD_MISS属性利用OFPIT_WRITE_ACTIONS指令,来描述表所支持的Set_Field行动类型。而OFPTFPT_APPLY_SETFIELD和OFPTFPT_APPLY_SETFIELD_MISS属性利用OFPIT_APPLY_ACTIONS指令,来描述表所支持的Set-Field行动类型。控制器max_entries字段异常,在ofp_table_features中的所有字段可能被要求改变。此字段是只读的,并且由交换机返回。OFPTFPT_APPLY_ACTIONS,OFPTFPT_APPLY_ACTIONS_MISS,OFPTFPT_APPLY_SETFIELD,和OFPTFPT_APPLY_SETFIELD_MISS属性包含表能运用的行动和字段。对于每一个列表,如果一个元素ispresent,意味着表至少能使该元素隔离一次。目前没有办法表示哪些元素能一起运用,按哪种顺序,一个元素能在一个单一的流表项里被运用多少次。OFPTFPT_EXPERIMENTER和OFPTFPT_EXPERIMENTER_MISS属性使用如下结构和字段:/*实验者的表的特征属性*/structofp_table_feature_prop_experimenter{uint16_ttype;/*OFPTFPT_EXPERIMENTER和OFPTFPT_EXPERIMENTER_MISS中之一.*/uint16_tlength;/*这个属性字节长度.*/uint32_texperimenter;/*ExperimenterID在ofp_experimenter_header结构中有相同形式.*/uint32_texp_type;/*实验者定义.*//*Followedby:*-Exactly(length-12)bytescontainingtheexperimenterdata,then*-Exactly(length+7)/8*8-(length)(between0and7)*bytesofall-zerobytes*/uint32_texperimenter_data[0];};OFP_ASSERT(sizeof(structofp_table_feature_prop_experimenter)==12);实验者字段是ExperimenterID,在ofp_experimenter结构体中有相同形式(见7.5.4).7.3.5.6端口统计关于端口统计的信息使用OFPMP_PORT_STATS复合请求类型进行请求:/*Bodyforofp_multipart_requestoftypeOFPMP_PORT.*/structofp_port_stats_request{uint32_tport_no;/*OFPMP_PORT消息必须请求统计,要么给一个单一的端口(在port_no中指定的)或者所有端口(port_no==OFPP_ANY).*/uint8_tpad[4];};OFP_ASSERT(sizeof(structofp_port_stats_request)==8);port_no字段有选择的过滤统计请求到给定的端口。若访问所有端口的统计,port_no必须设置成OFPP_ANY.回复部分由以下数组组成:/*OFPMP_PORT请求的回复部分.如果一个计数器不被支持,设置该字段给所有的(ones).*/structofp_port_stats{uint32_tport_no;uint8_tpad[4];/*排到-bits.*/uint_trx_packets;/*收到包的数量.*/uint_ttx_packets;/*已传送包的数量*/uint_trx_bytes;/*收到的字节数.*/uint_ttx_bytes;/*传送的字节数.*/uint_trx_dropped;/*被RX丢弃的包数.*/uint_ttx_dropped;/*被TX丢弃的包数.*/uint_trx_errors;/*接受到错误的数量.这是一个超集(super-set)更具体的接收错误,应该大于或等于所有rx_*_err值的总和。*/uint_ttx_errors;/*传送错误的数量.这是一个超集更具体的传输错误,应该大于或等于所有tx_*_err值的总和(没有当前定义的。)*/uint_trx_frame_err;/*帧调整的错误数量.*/uint_trx_over_err;/*在RX溢出的数据包数.*/uint_trx_crc_err;/*CRC错误数.*/uint_tcollisions;/*冲突数量.*/uint32_tduration_sec;/*端口已经生存了的秒数.*/uint32_tduration_nsec;/*端口已生存的时间超过duration_sec的纳秒数.*/};OFP_ASSERT(sizeof(structofp_port_stats)==112);duration_sec和duration_nsec字段表示端口已配置成OpenFlow通道已过去的时间。持续的总的纳秒数可以被算成duration_sec*10^9+duration_nsec.实现时要求提供第二精度,在能获得的条件下鼓励提供更高的精度。7.3.5.7端口描述

端口描述请求OFPMP_PORT_DESCRIPTION能使控制器获得支持OpenFlow系统里所有的端口描述。请求部分是空的。回复部分由如下数组构成:/*一个端口的描述*/structofp_port{uint32_tport_no;uint8_tpad[4];uint8_thw_addr[OFP_ETH_ALEN];uint8_tpad2[2];/*排到bits.*/charname[OFP_MAX_PORT_NAME_LEN];/*Null-terminated*/uint32_tconfig;/*OFPPC_*flags的位图.*/uint32_tstate;/*OFPPS_*flags的位图.*//*描述特性的OFPPF_*的位图.如果不支持或不可用的所有位清零*/uint32_tcurr;/*当前特征*/uint32_tadvertised;/*端口公布的特性.*/uint32_tsupported;/*端口支持的特性.*/uint32_tpeer;/*对端公布的特性.*/uint32_tcurr_speed;/*当前端口的比特率,kbps.*/uint32_tmax_speed;/*最大端口比特率kbps*/};OFP_ASSERT(sizeof(structofp_port)==);这个结构被描述在7.2.1.7.3.5.8队列统计OFPMP_QUEUE复合请求消息提供队列统计给一个或多个端口和一个或多个队列。请求部分包含一个port_no字段为请求的统计标识出OpenFlow端口,或者OFPP_ANY去查阅所有的端口。queue_id字段识别优先队列之一。或者OFPQ_ALL指向在指定端口配置的所有队列。OFPQ_ALL是0xffffffff。structofp_queue_stats_request{uint32_tport_no;/*如果是OFPP_ANY表示所有端口.*/uint32_tqueue_id;/*如果是OFPQ_ALL表示所有队列.*/};OFP_ASSERT(sizeof(structofp_queue_stats_request)==8);回复部分由下列结构组成:structofp_queue_stats{uint32_tport_no;uint32_tqueue_id;/*队列i.d*/uint_ttx_bytes;/*传送的字节数.*/uint_ttx_packets;/*传送的包数.*/uint_ttx_errors;/*由于溢出丢弃的数据包数量.*/uint32_tduration_sec;/*队列已经生成的秒数.*/uint32_tduration_nsec;/*队列已经生成超出duration_sec的纳秒数.*/};OFP_ASSERT(sizeof(structofp_queue_stats)==40);Duration_sec和duration_nsec字段表示队列已经安装在交换机里过去了的时间。持续的总时间可以用duration_sec*10^9+duration_nsec.实现时要求提供第二精度,在能获得的条件下鼓励提供更高的精度。7.3.5.9组统计OFPMP_GROUP复合请求消息为一个或多个组提供统计。请求部分由group_id字段组成。它也能被设置为OFPG_ALL表示交换机里所有的组。/*OFPMP_GROUP请求部分.*/structofp_group_stats_request{uint32_tgroup_id;/*如果是OFPG_ALL表示所有的表.*/uint8_tpad[4];/*拍到bits.*/};OFP_ASSERT(sizeof(structofp_group_stats_request)==8);回复部分由如下结构组成:/*回复给OFPMP_GROUP请求的部分.*/structofp_group_stats{uint16_tlength;/*这个流表项的长度.*/uint8_tpad[2];/*排到bits.*/uint32_tgroup_id;/*组标识符.*/uint32_tref_count;/*直接指向该组的流或组的数量*/uint8_tpad2[4];/*排到bits.*/uint_tpacket_count;/*组处理过的包的数量.*/uint_tbyte_count;/*组处理过的字节数量.*/uint32_tduration_sec;/*组已经生存的秒数.*/uint32_tduration_nsec;/*组已经生存的超过duration_sec的纳秒数.*/structofp_bucket_counterbucket_stats[0];/*每个存储段设置一个计数器.*/};OFP_ASSERT(sizeof(structofp_group_stats)==40);字段包括创建组的group_mod提供的,加上ref_count表示计算与组相关的流的数量,packet_count,和byte_count计算所有组处理的数据包。Duration_sec和duration_nsec字段表示组安装在交换机里已经过去的时间。总的持续的纳秒数可以用duration_sec*10^9+duration_nsec.实现时要求提供第二精度,在能获得的条件下鼓励提供更高的精度。Bucket_stats字段由一组ofp_bucket_counter结构体组成:/*用来做组统计回复.*/structofp_bucket_counter{uint_tpacket_count;/*存储段处理的包数.*/uint_tbyte_count;/*存储段处理的字节数.*/};OFP_ASSERT(sizeof(structofp_bucket_counter)==16);7.3.5.10组描述OFPMP_GROUP_DESC复合请求消息提供一个方式将交换机上的组设置列出来,以及它们相应的存储段行动。请求部分是空的,而回复部分是如下结构的数组:/*回复给OFPMP_GROUP_DESC请求的部分.*/structofp_group_desc{uint16_tlength;/*流表项的长度.*/uint8_ttype;/*OFPGT_*中之一.*/uint8_tpad;/*填充至bits.*/uint32_tgroup_id;/*组标识符.*/structofp_bucketbuckets[0];/*存储段列表--0或更多.*/};OFP_ASSERT(sizeof(structofp_group_desc)==8);描述组的字段和那些ofp_group_mod结构体使用的一样(见7.3.4.2)。7.3.5.11组特征OFPMP_GROUP_FEATURES复合请求消息提供一个方式列出交换机上组的功能。请求部分是空的,而回复部分是如下结构:/*回复给OFPMP_GROUP_FEATURES请求的部分.组特征.*/structofp_group_features{uint32_ttypes;/*OFPGT_*值支持的位图.*/uint32_tcapabilities;/*OFPGFC_*功能支持的位图.*/uint32_tmax_groups[4];/*每个类型的组的最大数量.*/uint32_tactions[4];/*支持的OFPAT_*的位图.*/};OFP_ASSERT(sizeof(structofp_group_features)==40);max_groups字段是每个类型的组的最大数量。行动是每个组类型支持的行动。功能使用如下标志的一个组合:/*组配置标志*/enumofp_group_capabilities{OFPGFC_SELECT_WEIGHT=1<<0,/*选择组支持的重量*/OFPGFC_SELECT_LIVENESS=1<<1,/*选择组支持的活跃度*/OFPGFC_CHAINING=1<<2,/*支持链接组*/OFPGFC_CHAINING_CHECKS=1<<3,/*为循环检查和删除链接*/7.3.5.12计量器统计OFPMT_METER统计请求消息给一个或多个计量器提供统计。请求部分由一个meter_id字段组成,它能设置成OFPM_ALL表示交换机上所有计量器。/*OFPMP_METER和OFPMP_METER_CONFIG请求部分*/structofp_meter_multipart_request{uint32_tmeter_id;/*计量器实例,或者是OFPM_ALL.*/uint8_tpad[4];/*排列到bits.*/};OFP_ASSERT(sizeof(structofp_meter_multipart_request)==8);回复部分是如下结构:/*OFPMP_METER请求的回复部分.计量器统计.*/structofp_meter_stats{uint32_tmeter_id;/*计量器例子*/uint16_tlen;/*统计的字节长度.*/uint8_tpad[6];uint32_tflow_count;/*跳至计量器的流数量.*/uint_tpacket_in_count;/*输入数据包的数量.*/uint_tbyte_in_count;/*输入的字节数.*/uint32_tduration_sec;/*计量器已经生成了的秒数.*/uint32_tduration_nsec;/*计量器已经生存超出duration_sec的纳秒数.*/structofp_meter_band_statsband_stats[0];/*band_stats长度是字段长度里推出来的*/};OFP_ASSERT(sizeof(structofp_meter_stats)==40);packet_in_count和byte_in_count对计量器处理过的所有数据包进行计数。duration_sec和duration_nsec字段表示计量器安装在交换机上过去了的时间。总的持续时间可以用duration_sec*10^9+duration_nsec。实现时要求提供第二精度,在能获得的条件下鼓励提供更高的精度。band_stats字段由ofp_meter_band_stats结构组成:/*给每个计量带宽的统计*/structofp_meter_band_stats{uint_tpacket_band_count;/*带内的数据包数量.*/uint_tbyte_band_count;/*带内的字节数量.*/};OFP_ASSERT(sizeof(structofp_meter_band_stats)==16);packet_band_count和byte_band_count对带宽处理的数据包进行计数。带宽统计的顺序必须和OFPMT_METER_CONFIG统计回复里的一样。7.3.5.13计量器配置统计OFPMT_METER_CONFIG统计请求消息给一个或多个计量器提供配置。请求部分由一个meter_id字段组成,它可以被设置成OFPM_ALL表示交换机上所有的计量器。/*OFPMP_METER和OFPMP_METER_CONFIG请求部分.*/structofp_meter_multipart_request{uint32_tmeter_id;/*计量器实例,或者OFPM_ALL.*/uint8_tpad[4];/*对齐到bits.*/};OFP_ASSERT(sizeof(structofp_meter_multipart_request)==8);回复部分由一个如下结构组成:/*OFPMP_METER_CONFIG请求的回复部分.计量器配置*/structofp_meter_config{uint16_tlength;/*流表项的长度.*/uint16_tflags;/*AllOFPMC_*表示申请.*/uint32_tmeter_id;/*计量器实例.*/structofp_meter_band_headerbands[0];/*带宽的长度从字段长度里推导出*/};OFP_ASSERT(sizeof(structofp_meter_config)==8);该字段和用来配置计量器的字段相同(见7.3.4.4)7.3.5.14仪表功能统计OFPMT_METER_FEATRUES统计请求消息提供了计量子系统功能集合。请求部分是空的,和回复部分由以下结构组成:/*回复ofpmp_meter_features请求。计量功能*/structofp_meter_features{uint32_tmax_meter;/*计量器的最大数值.*/uint32_tband_types;/*支持位图ofpmbt_*的值*/uint32_tcapabilities;/*ofp_meter_flags的位图*/uint8_tmax_bands;/*每个计量的的最大频带*/uint8_tmax_color;/*最大的彩色值*/uint8_tpad[2];};OFP_ASSERT(sizeof(structofp_meter_features)==16);7.3.5.15实验者复合实验者特定复合消息通过OFPMP_EXPERIMENTER复合类型进行请求,请求的第一个字节和回复部分结构如下:/*ofp_multipart_request部分/回复OFPMP_EXPERIMENTER.*/structofp_experimenter_multipart_header{uint32_texperimenter;/*实验者标识符,与ofp_experimenter_header中格式相同*/uint32_texp_type;/*实验者定义*//*实验者自定义附加数据*/};OFP_ASSERT(sizeof(structofp_experimenter_multipart_header)==8);剩余的请求和回复部分是由实验者定义experimenter字段是实验者的ID,与OFPMP_EXPERIMENTER中的格式相同。7.3.6队列配置消息队列配置超出了OpenFlow协议范围,可通过一个命令行工具,或通过一个外部的专用配置协议。控制器使用下列结构来查询交换机端口上已配置队列:/*查询端口队列配置*/structofp_queue_get_config_request{structofp_headerheader;uint32_tport;/*查询的端口;应该指向一个有效的物理端口(或OFPP_ANY要求所有配置队列)*/uint8_tpad[4];};OFP_ASSERT(sizeof(structofp_queue_get_config_request)==16);交换机使用OFP_QUEUE_GET_CONFIG_REPLY命令回复,其中包含配置队列的列表。/*给定端口的队列配置*/structofp_queue_get_config_reply{structofp_headerheader;uint32_tport;uint8_tpad[4];structofp_packet_queuequeues[0];/*已配置的队列列表*/};OFP_ASSERT(sizeof(structofp_queue_get_config_reply)==16);7.3.7分组报文当控制器通过数据通路发送一个数据包,就使用OFPT_PACKET_OUT消息:/*发送数据包(控制器->通路)*/structofp_packet_out{structofp_headerheader;uint32_tbuffer_id;/*指定的标识符通过数据通路(OFP_NO_BUFFER如果没有)*/uint32_tin_port;/*分组的输入端口或OFPP_CONTROLLER*/uint16_tactions_len;/*以字节数组的大小的作用*/uint8_tpad[6];structofp_action_headeractions[0];/*行动列表-0或更多*//*可变大小的行动清单可在后面跟着分组数据。*如果buffer_id=-1目前的数据是有意义的。/*uint8_t数据[0];*//*分组数据长度是从长度字段的头部计算的*/};OFP_ASSERT(sizeof(structofp_packet_out)==24buffer_id与ofp_packet_in消息中给出的是相同的。如果buffer_id是OFP_NO_BUFFER,则数据包位于数据阵列中,和封装在消息里的数据包由行动的消息进行处理。OFP_NO_BUFFER等于0xffffffff。如果buffer_id是有效的,相关的端口被行动消息从缓冲区删除。in_port字段表示入端口,端口必须与OpenFlow处理数据包相关。它必须设置为一个有效的标准交换机端口(见4.2)或OFPP_CONTROLLER.例如,当使用OFPP_TABLE,OFPP_IN_PORT,OFPP_ALL和组处理数据包时就使用这个字段。Action是一个行动列表定义交换机如何处理数据包的字段。可包括包修改,组处理和一个输出端口。一个OFPT_PACKET_OUT行动清单消息也可以指定OFPP_TABLE保留端口作为输出行动来处理OpenFlow流水线中的数据包,从第一个流表开始(见4.5)。如果OFPP_TABLE被指定,in_port作为查找时流表的入端口。在某些情况下,发送到OFPP_TABLE的数据包,经过流表项行动或漏表后,可能转发给控制器。对这样控制器到交换机回路的检测和执行行动不在本规范范围内。一般来说,OpenFlow的消息不保证是顺序处理。因此,如果一个使用OFPP_TABLE的OFPP_TABLE消息依赖于最近发送到交换机(与OFPT_FLOW_MOD消息)的流,一个OFPT_BARRIER_REQUEST消息需要在OFPT_PACKET_OUT消息之前,确保在执行OFPP_TABLE之前把流表项交给流表。7.3.8屏障消息当控制器要想确保消息已送到或想接收到通知来完成操作,它可以使用一个OFPT_BARRIER_REQUEST消息。此消息没有内容。收到后,在执行基于BarrierRequest任何消息之前,交换机必须处理完所有先前收到的信息,包括发送相应的回复或错误信息。当处理完成,交换机必须发送一个消息OFPT_BARRIER_REPLY携带XID最初的请求。7.3.9任务请求消息当控制器要转变角色,它使用OFPT_ROLE_REQUEST消息,结构如下:/*请求和回复消息的角色*/structofp_role_request{structofp_headerheader;/*ofpt_role_request/ofpt_role_reply型*/uint32_trole;/*ofpcr_role_*之一*/uint8_tpad[4];/*对齐到位*/uint_tgeneration_id;/*主设备选择产生的标识符*/};OFP_ASSERT(sizeof(structofp_role_request)==24);role字段就是控制器要担任的新角色,并且可以有以下值:/*控制器的角色*/enumofp_controller_role{OFPCR_ROLE_NOCHANGE=0,/*不改变目前的角色*/OFPCR_ROLE_EQUAL=1,/*默认角色,完全访问。*/OFPCR_ROLE_MASTER=2,/*完全访问,最多一个主设备。*/OFPCR_ROLE_SLAVE=3,/*只读访问*/};如果消息中的角色值是OFPCR_ROLE_MASTER或OFPCR_ROLE_SLAVE,交换机必须验证generation_id检查过期消息(见6.3.4)。如果验证失败,交换机必须抛弃角色要求和返回OFPET_ROLE_REQUEST_FAILED类型和OFPRRFC_STALE代码的错误消息。如果角色值是OFPCR_ROLE_MASTER,所有其他角色是OFPCR_ROLE_MASTER的控制器都要改变为OFPCR_ROLE_SLAVE(见6.3.4)。如果角色值是OFPCR_ROLE_NOCHANGE,控制器当前的角色就不改变;这使控制器查询其目前的角色而无需改变它。收到一个OFPT_ROLE_REQUEST的消息后,如果没有错误,交换机必须返回一个OFPT_ROLE_REPLY消息。这则消息的结构与OFPT_ROLE_REQUEST消息是完全一样的,role字段就是当前控制的角色。generation_id设置为当前generation_id(上一次成功角色请求的generation_id,角色是OFPCR_ROLE_MASTER或OFPCR_ROLE_SLAVE),如果目前的generation_id控制器没有设置,回复中的generation_id必须设置为最大字段(无符号值相当于-1)。7.3.10设置异步配置信息在一个给定的OpenFlow通道上,分别使用OFPT_SET_ASYNC和OFPT_GET_ASYNC_REQUEST消息,控制器能设置和查询它想要接收的异步消息(除错误消息)。交换机使用OFPT_GET_ASYNC_REPLY消息响应一个OFPT_GET_ASYNC_REQUEST消息;它不回复一个设置配置的请求。基于OpenFlow头部的OFPT_GET_ASYNC_REQUEST消息没有body。OFPT_SET_ASYNC和OFPT_GET_ASYNC_REPLY消息的格式如下:/*异步消息的配置。*/structofp_async_config{structofp_headerheader;/*OFPT_GET_ASYNC_REPLYorOFPT_SET_ASYNC.*/uint32_tpacket_in_mask[2];/*ofpr_*值的位掩码*/uint32_tport_status_mask[2];/*ofppr_*值的位掩码。*/uint32_tflow_removed_mask[2];/*ofprr_*值的位掩码。.*/};OFP_ASSERT(sizeof(structofp_async_config)==32);结构structofp_async_config包含三个二维数组。每个数组控制是否接收控制器一个特定的枚举ofp_type异步消息。当控制器是OFPCR_ROLE_EQUAL或OFPCR_ROLE_MASTER角色时,每个数组中的元素0表示感兴趣的消息。当控制器是OFPCR_ROLE_SLAVE角色时,元素为1。每个数组元素的位掩码中的0禁止接收与比特位置有关的reason代码消息。而1则可以接收。例如,在port_status_mask[1]中比特值为2

2=4,当控制器的角色是OFPCR_ROLE_SLAVE时,决定控制器是否接收理由是OFPPR_MODIFY(值为2)的OFPT_PORT_STATUS消息。OFPT_SET_ASYNC设置控制器是否应该接受一个交换机产生的异步消息。其他的OpenFlow功能控制是否产生一个给定的消息;例如,在OFPFF_SEND_FLOW_REM标志控制交换机在流表项删除时是否产生OFPT_FLOW_REMOVED消息。。一个交换机的配置,例如使用OpenFlow配置协议,一旦OpenFlow建立连接,就可以设置异步消息的初始配置。交换机没有配置的话,初始配置应:在“master”或“equal”的角色,使能所有的OFPT_PACKET_IN消息,除了那些带有OFPR_INVALID_TTL原因的,使能所有的OFPT_PORT_STATUS和OFPT_FLOW_REMOVED消息。在“slave”角色,使能所有OFPT_PORT_STATUS消息,并禁用所有OFPT_PACKET_IN和OFPT_FLOW_REMOVED的消息。利用OFPT_SET_ASYNC的配置设置是针对一个特定的OpenFlow的通道,它不会影响任何其他OpenFlow通道,无论是目前建立的或是以后建立的。配置设置OFPT_SET_ASYNC不过滤器或影响的错误消息。7.4异步消息7.4.1包输入消息当数据包通过数据通路进行接收和发送给控制器,都使用OFPT_PACKET_IN消息:/*端口接收到的数据包(数据通路->控制器)*/structofp_packet_in{structofp_headerheader;uint32_tbuffer_id;/*分配的数据通路ID。*/uint16_ttotal_len;/*帧全长*/uint8_treason;/*包被发送的原因(一个ofpr_*)*/uint8_ttable_id;/*被查询的流表标识符*/uint_tcookie;/*查询的流表项cookie*/structofp_matchmatch;/*分组元数据。可变尺寸。*//*可变大小和填充匹配总是跟着:*2个全零填充字节,然后是以太网帧,其长度是根据header.length推断。*以太网帧前填充的字节,确保以太网报头后的IP头部(如果有的话)是32位*///uint8_tpad[2];/*对齐位+16位*///uint8_tdata[0];/*以太网帧*/};OFP_ASSERT(sizeof(structofp_packet_in)==32);buffer_id是个不透明的值,数据通路使用它识别一个缓冲数据包。当一个数据包进行缓存,消息的某些字节将包含在消息的数据部分。如果数据包是因为“发送给控制器”的行动而发送,那么流建立请求的ofp_action_output会发送max_len字节。如果数据包其他原因发送,如无效的TTL,然后OFPT_SET_CONFIG消息至少发送miss_send_len字节。默认miss_send_len是128字节。如果数据包没有缓冲-要么是因为没有可用的缓冲区,或因明确表示通过OFPCML_NO_BUFFER请求-整个数据包都包含在数据部分,而且buffer_id就是OFP_NO_BUFFER。

实现缓冲的交换机希望通过文档公开,可用的缓冲数量和缓冲区可重复使用前的时间长度。交换机必须妥善处理这样的事件,当一个packet_in消息缓冲,而控制器没有反应的情况。交换机应防止缓冲区被重复使用,直到它已由控制器处理,或经过一段时间(文档中说明)。data字段包含的数据包本身,或缓冲包的一小部分。包头部反映了前面处理对数据包的任何变化。reason字段可以是这些值的某个:/*为什么这个包被发送到控制器?*/enumofp_packet_in_reason{OFPR_NO_MATCH=0,/*没有匹配的流(漏表流表项)*/OFPR_ACTION=1,/*输出给控制器的行动。*/OFPR_INVALID_TTL=2,/*包有无效的TTL*/};OFPR_INVALID_TTL表明携带无效的IPTTL或MPLSTTL被OpenFlow流水线拒绝并传给控制器。不需要对每一个数据包都进行无效的TTL检查,但它至少在每次OFPAT_DEC_MPLS_TTL或OFPAT_DEC_NW_TTL行动应用到一个包时进行检查。cookie字段包含导致包被发送到控制器的流表项cookie。如果一个cookie不能与一个特定的流有关的,这字段必须设置为-1(0xffffffffffffffff)。例如,如果包输入是在组存储段里或从行动集产生的。当有事件触发包输入消息发生,同时包含一组OXMTLVs,match字段就反映分组的头部和上下午。这个上下文包括与数据包以前处理发生的任何改变,包括已经执行的行动,行动集的任何变化,除了无任何变化的。这OXMTLVs必须包括上下文字段,也就是,其值不能从数据包确定的字段。标准的上下文字段是OFPXMT_OFB_IN_PORT,OFPXMT_OFB_IN_PHY_PORT,OFPXMT_OFB_METADATA和OFPXMT_OFB_TUNNEL_ID.所有位都是零的字段应忽略。OXMTLVs可包括先前从分组中提取的数据包头部字段,也包括那些在处理过程中的任何修改。当在物理端口直接收到一个包时,而且未被逻辑端口处理,OFPXMT_OFB_IN_PORT和OFPXMT_OFB_IN_PHY_PORT有相同的值,OpenFlow物理端口的portno。OFPXMT_OFB_IN_PHY_PORT如果与OFPXMT_OFB_IN_PORT有相同的值则应忽略。当一个包是通过一个物理端口的逻辑端口上接收的,OFPXMT_OFB_IN_PORT是逻辑端口的端口的portno,OFPXMT_OFB_IN_PHY_PORT是物理端口的portno。例如,考虑一个包在隧道接口上接收,接口是由两个物理端口的链路汇聚组(LAG)进行定义的。如果隧道接口是绑定到OpenFlow的逻辑端口,那么OFPXMT_OFB_IN_PORT是隧道portno,OFPXMT_OFB_IN_PHY_PORT是已配置隧道的LAG物理端口portno成员。OFPXMT_OFB_IN_PORTTLV引用的端口必须是用来匹配流表项的端口(见5.3),也必须对OpenFlow处理有用(即OpenFlow可以转发数据包到该端口,依靠端口标志)。OFPXMT_OFB_IN_PHY_PORT不需要有效匹配或进行OpenFlow处理。7.4.2流删除消息如果控制器请求通知流表项超时或从表中删除(见5.5),数据通路使用OFPT_FLOW_REMOVED消息:/*流删除(数据通路->控制器)*/structofp_flow_removed{structofp_headerheader;uint_tcookie;/*不透明的控制器发出标识符。*/uint16_tpriority;/*流表项优先级。*/uint8_treason;/*一个ofprr_*uint8_ttable_id;/*流表的标识符*/uint32_tduration_sec;/*Timeflowwasaliveinseconds.*/uint32_tduration_nsec;/*Timeflowwasaliveinnanosecondsbeyondduration_sec.*/uint16_tidle_timeout;/*从原来的flowmod空闲超时*/uint16_thard_timeout;/*从原来的flowmod硬超时。*/uint_tpacket_count;uint_tbyte_count;structofp_matchmatch;/*字段描述。可变尺寸。*/};OFP_ASSERT(sizeof(structofp_flow_removed)==56);Match,cookie,和priority字段与那些在flowmod请求里使用的相同。Reason字段是下列之一:/*为什么流中删除?*/enumofp_flow_removed_reason{OFPRR_IDLE_TIMEOUT=0,/*流idle_timeout空闲时间超过*/OFPRR_HARD_TIMEOUT=1,/*时间超过hard_timeout。*/OFPRR_DELETE=2,/*由DELETEflowmod消除。*/OFPRR_GROUP_DELETE=3,/*删除的组。*/};duration_sec和duration_nsec字段在第7.3.5.2描述。idle_timeout和hard_timeout字段是直接从创建流表项的flowmod复制。利用上述三个字段,你可以找到流表项活跃的时间,以及流表项接收信息的时间。packet_count和byte_count分别表示与流表项相关联的包和字节的数值。这些计数器应像其他统计计数器(见7.3.5);如果没有设置,它们都是无符号的,并应设置为字段最大值。7.4.3端口的状态信息当端口被添加,修改,从数据通路中删除,利用OFPT_PORT_STATUS消息告知控制器:/*数据通路的一个物理端口改变*/structofp_port_status{structofp_headerheader;uint8_treason;/*一个ofppr_*/uint8_tpad[7];/*对齐到位。*/structofp_portdesc;};OFP_ASSERT(sizeof(structofp_port_status)==80);reason可以是下列值之一:/*是什么改变了关于物理端口*/enumofp_port_reason{OFPPR_ADD=0,/*端口添加。*/OFPPR_DELETE=1,/*端口被删除*/OFPPR_MODIFY=2,/*某些端口的属性已经改变了。*/};7.4.4错误消息交换机需要把问题通知给控制器。这是通过OFPT_ERROR_MSG消息完成:/*ofpt_error:错误消息(数据通路->控制器)。*/structofp_error_msg{structofp_headerheader;uint16_ttype;uint16_tcode;uint8_tdata[0];/*可变长度的数据。用类型和代码区分。无填充*/};OFP_ASSERT(sizeof(structofp_error_msg)==12);Type的值表示错误的高层次的类型。代码值是在类型基础上解析。数据是可变长度的并且基于类型和代码解析。除非另有规定data字段包含至少字节的失败请求,导致错误消息产生,如果失败请求小于字节,它应该是完整的请求而无填充。如果错误消息是来自控制器的响应,例如,OFPET_BAD_REQUEST,

OFPET_BAD_ACTION,OFPET_BAD_INSTRUCTION,OFPET_BAD_MATCH,或OFPET_FLOW_MOD_FAILED,那么头部的xid字段必须匹配那个引起错误的消息。以_EPERM结束的错误代码表示一个允许产生的错误,例如,控制器和交换机之间插入一个OpenFlow管理程序。目前定义的错误类型是:/*ofp_error_message里的“type”值。这些值是不变的:他们不会在未来版本的协议改变(虽然新值可以添加)。*/enumofp_error_type{OFPET_HELLO_FAILED=0,/*hello协议失败*/OFPET_BAD_REQUEST=1,/*请求不被理解*/OFPET_BAD_ACTION=2,/*在行动中描述的错误。*/OFPET_BAD_INSTRUCTION=3,/*指令表中错误。*/OFPET_BAD_MATCH=4,/*错误匹配。*/OFPET_FLOW_MOD_FAILED=5,/*修改流表项问题。*/OFPET_GROUP_MOD_FAILED=6,/*修改组表项问题。*/OFPET_PORT_MOD_FAILED=7,/*端口属性请求失败。*/OFPET_TABLE_MOD_FAILED=8,/*流表请求失败*/OFPET_QUEUE_OP_FAILED=9,/*队列操作失败*/OFPET_SWITCH_CONFIG_FAILED=10,/*交换机配置请求失败*/OFPET_ROLE_REQUEST_FAILED=11,/*控制器任务请求失败*/OFPET_METER_MOD_FAILED=12,/*计量器错误*/OFPET_TABLE_FEATURES_FAILED=13,/*设置流表功能失败*/OFPET_EXPERIMENTER=0xffff/*实验者的错误消息*/};为OFPET_HELLO_FAILED错误type,下面是目前定义的codes:/*为OFPET_HELLO_FAILEDofp_error_msg“code”的值。Data包含ASCII文本字符串,可以提供详细的故障。*/enumofp_hello_failed_code{OFPHFC_INCOMPATIBLE=0,/*不兼容的版本*/OFPHFC_EPERM=1,/*允许失败*/};Data字段包含ASCII文本字符串,加上为什么发生错误的细节。为OFPET_BAD_REQUEST错误type,下面是目前定义的code:/*为OFPET_BAD_REQUESTofp_error_msg“code”的值。Data至少包含请求失败的第一个字节。*/enumofp_bad_request_code{OFPBRC_BAD_VERSION=0,/*ofp_header.版本不支持。*/OFPBRC_BAD_TYPE=1,/*ofp_header.type不支持的类型*/OFPBRC_BAD_MULTIPART=2,/*ofp_multipart_request.type类型不支持*/OFPBRC_BAD_EXPERIMENTER=3,/*不支持的实验者身份ID(在ofp_experimenter_header或ofp_multipart_request或ofp_multipart_reply)。*/OFPBRC_BAD_EXP_TYPE=4,/*实验者类型不支持。*/OFPBRC_EPERM=5,/*允许误差*/OFPBRC_BAD_LEN=6,/*类型错误的请求长度。*/OFPBRC_BUFFER_EMPTY=7,/*已被使用的指定缓冲区。*/OFPBRC_BUFFER_UNKNOWN=8,/*指定的缓冲区不存在。*/OFPBRC_BAD_TABLE_ID=9,/*指定的表标识符无效或不存在。*/OFPBRC_IS_SLAVE=10,/*拒绝因为控制器是从设备*/OFPBRC_BAD_PORT=11,/*无效的端口*/OFPBRC_BAD_PACKET=12,/*包输出里无效的数据包*/OFPBRC_MULTIPART_BUFFER_OVERFLOW=13,/*ofp_multipart_request分配的缓冲区溢出*/下面是目前定义OFPET_BAD_ACTION错误type的code:/*OFPET_BAD_INSTRUCTIONofp_error_msg'code'的值。数据至少包含请求失败的第一个字节*/enumofp_bad_action_code{OFPBAC_BAD_TYPE=0,/*未知的行动类型。*/OFPBAC_BAD_LEN=1,/*行动的长度问题。*/OFPBAC_BAD_EXPERIMENTER=2,/*未知的实验者指定标识符*/OFPBAC_BAD_EXP_TYPE=3,/*实验者的标识符。未知的行动*/OFPBAC_BAD_OUT_PORT=4,/*问题有效输出端口。*/OFPBAC_BAD_ARGUMENT=5,/*不良行为的论证*/OFPBAC_EPERM=6,/*允许的错误*/OFPBAC_TOO_MANY=7,/*不能处理这么多的行动。*/OFPBAC_BAD_QUEUE=8,/*问题验证输出队列。*/OFPBAC_BAD_OUT_GROUP=9,/*在转发的动作无效组标识符*/OFPBAC_MATCH_INCONSISTENT=10,/*行动不能申请匹配,或设置字段丢失的前提。*/OFPBAC_UNSUPPORTED_ORDER=11,/*应用行动指令的行动列表不支持行动排序*/OFPBAC_BAD_TAG=12,/*行动使用不支持的标签/封装。*/OFPBAC_BAD_SET_TYPE=13,/*在set_field行动不支持的类型。*/OFPBAC_BAD_SET_LEN=14,/*在set_field行动长度问题。*/OFPBAC_BAD_SET_ARGUMENT=15,/*在set_field行动不好的论据*/};下面是目前定义为OFPET_BAD_INSTRUCTION错误type的code:/*为OFPET_BAD_INSTRUCTIONofp_error_msg“code”的值。数据至少包含请求失败的第一个字节。*/enumofp_bad_instruction_code{OFPBIC_UNKNOWN_INST=0,/*未知的指令*/OFPBIC_UNSUP_INST=1,/*交换机或表不支持的指令。*/OFPBIC_BAD_TABLE_ID=2,/*指定流表标识符无效。*/OFPBIC_UNSUP_METADATA=3,/*元数据值不支持的数据通路。*/OFPBIC_UNSUP_METADATA_MASK=4,/*元数据的掩码值不支持的数据通路。*/OFPBIC_BAD_EXPERIMENTER=5,/*未知的实验者指定标识符。*/OFPBIC_BAD_EXP_TYPE=6,/*实验者未知指令标识符。*/OFPBIC_BAD_LEN=7,/*在指令长度的问题。*/OFPBIC_EPERM=8,/*允许的错误。*/};为OFPET_BAD_MATCH错误type,下面是目前定义的code:/*为OFPET_BAD_MATCHofp_error_msg“code”的值。数据至少包含请求失败的第一个字节。*/enumofp_bad_match_code{OFPBMC_BAD_TYPE=0,/*不支持匹配指定的匹配类型*/OFPBMC_BAD_LEN=1,/*匹配长度问题*/OFPBMC_BAD_TAG=2,/*匹配采用不支持的标签/封装。*/OFPBMC_BAD_DL_ADDR_MASK=3,/*不支持的数据地址掩码–交换机不支持任意链路地址掩码。*/OFPBMC_BAD_NW_ADDR_MASK=4,/*不支持的网络地址掩码–交换机不支持任意网络地址掩码。*/OFPBMC_BAD_WILDCARDS=5,/*不支持的域掩蔽或在匹配中省略的组合*/OFPBMC_BAD_FIELD=6,/*在匹配中不支持的字段类型。*/OFPBMC_BAD_VALUE=7,/*在匹配域不受支持的值。*/OFPBMC_BAD_MASK=8,/*不支持匹配中指定的掩码,字段不是dl_address或nw_address。*/OFPBMC_BAD_PREREQ=9,/*一个先决条件不满足。*/OFPBMC_DUP_FIELD=10,/*一种字段类型是重复的。*/OFPBMC_EPERM=11,/*允许的错误。*/};FortheOFPET_FLOW_MOD_FAILEDerrortype,thefollowingcodesarecurrentlyde_ned:对于OFPET_TABLE_MOD_FAILED错误type,下面是目前定义的代码:/*对于OFPET_TABLE_MOD_FAILED的ofp_error_msg“code”的值。”data至少包含请求失败第一个字节的。*/enumofp_flow_mod_failed_code{OFPFMFC_UNKNOWN=0,/*未指定的错误*/OFPFMFC_TABLE_FULL=1,/*因为表已满,流不能添加。*/OFPFMFC_BAD_TABLE_ID=2,/*流表不存在*/OFPFMFC_OVERLAP=3,/*使用check_overlap标志尝试添加重叠的流*/OFPFMFC_EPERM=4,/*允许的错误。*/OFPFMFC_BAD_TIMEOUT=5,/*因为不支持空闲/硬超时,流表不被添加。*/OFPFMFC_BAD_COMMAND=6,/*不支持的或未知的命令。*/OFPFMFC_BAD_FLAGS=7,/*不支持的或未知的标志。*/};对于OFPET_SWITCH_CONFIG_FAILED错误type,下面是目前定义的code:/*为OFPET_SWITCH_CONFIG_FAILED的ofp_error_msg“code”的值。”data至少包含请求失败第一个字节的*/enumofp_group_mod_failed_code{OFPGMFC_GROUP_EXISTS=0,/*组不添加因为组添加试图取代一个已经存在的组*/OFPGMFC_INVALID_GROUP=1,/*组不能添加因为组指定的组是无效的*/OFPGMFC_WEIGHT_UNSUPPORTED=2,/*交换机在所选组中不支持不均等的负荷分担*/OFPGMFC_OUT_OF_GROUPS=3,/*组表已满。*/OFPGMFC_OUT_OF_BUCKETS=4,/*组的行动存储段已超过最大值。*/OFPGMFC_CHAINING_UNSUPPORTED=5,/*交换机不支持需要转发去的组*/OFPGMFC_WATCH_UNSUPPORTED=6,/*这个组不能监视w指定的atch_port或watch_group。*/OFPGMFC_LOOP=7,/*组表项会引起循环*/OFPGMFC_UNKNOWN_GROUP=8,/*组不能修改,因为修改组试图修改一个不存在的组*/OFPGMFC_CHAINED_GROUP=9,/*组不能删除因为另一组是向其转发。*/OFPGMFC_BAD_TYPE=10,/*不支持的或未知的组类型*/OFPGMFC_BAD_COMMAND=11,/*不支持的或未知的命令。*/OFPGMFC_BAD_BUCKET=12,/*存储段里的错误*/OFPGMFC_BAD_WATCH=13,/*在观察端口/组的错误。*/OFPGMFC_EPERM=14,/*允许的错误。*/};下面是目前定义为OFPET_PORT_MOD_FAILED错误type的代码:/*OFPET_METER_MOD_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_port_mod_failed_code{OFPPMFC_BAD_PORT=0,/*指定的端口号不存在*/OFPPMFC_BAD_HW_ADDR=1,/*指定的硬件地址不匹配端口号*/OFPPMFC_BAD_CONFIG=2,/*指定的配置无效*/OFPPMFC_BAD_ADVERTISE=3,/*指定的标识符是无效的。*/OFPPMFC_EPERM=4,/*允许的错误.*/};下面是目前定义为OFPET_METER_MOD_FAILED错误type的code:/*OFPET_METER_MOD_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_table_mod_failed_code{OFPTMFC_BAD_TABLE=0,/*指定的流表不存在*/OFPTMFC_BAD_CONFIG=1,/*指定的配置无效*/OFPTMFC_EPERM=2,/*允许的错误*/};下面是目前定义为OFPET_TABLE_MOD_FAILED错误type的code:/*OFPET_TABLE_MOD_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_queue_op_failed_code{OFPQOFC_BAD_PORT=0,/*无效的端口(或端口不存在)*/OFPQOFC_BAD_QUEUE=1,/*队列不存在*/OFPQOFC_EPERM=2,/*允许的错误*/};下面是目前定义为OFPET_SWITCH_CONFIG_FAILED错误type的code:/*OFPET_SWITCH_CONFIG_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_switch_config_failed_code{OFPSCFC_BAD_FLAGS=0,/*指定的标志无效*/OFPSCFC_BAD_LEN=1,/*指定的长度无效*/OFPSCFC_EPERM=2,/*允许的错误*/};下面是目前定义为OFPET_ROLE_REQUEST_FAILED错误type的code:/*对于OFPET_ROLE_REQUEST_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_role_request_failed_code{OFPRRFC_STALE=0,/*过时消息:旧的generation_id.*/OFPRRFC_UNSUP=1,/*控制器不支持角色的变化*/OFPRRFC_BAD_ROLE=2,/*无效的角色*/};下面是目前定义为OFPET_METER_MOD_FAILED错误type的code:/*对于OFPET_METER_MOD_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_meter_mod_failed_code{OFPMMFC_UNKNOWN=0,/*未指定的错误.*/OFPMMFC_METER_EXISTS=1,/*计量器不加因为试图取代现有的计量器*/OFPMMFC_INVALID_METER=2,/*计量器不加因为指定的计量器是无效的*/OFPMMFC_UNKNOWN_METER=3,/*计量器不修改因为试图修改一个不存在的计量器*/OFPMMFC_BAD_COMMAND=4,/*不支持的或未知的命令*/OFPMMFC_BAD_FLAGS=5,/*配置的标志不支持*/OFPMMFC_BAD_RATE=6,/*速率不支持*/OFPMMFC_BAD_BURST=7,/*不支持的突发大小.*/OFPMMFC_BAD_BAND=8,/*频带不支持*/OFPMMFC_BAD_BAND_VALUE=9,/*频带值不被支持*/OFPMMFC_OUT_OF_METERS=10,/*没有更多的计量器有效*/OFPMMFC_OUT_OF_BANDS=11,/*对于计量器的属性数量已超过最大值.*/};下面是目前定义为OFPET_TABLE_FEATURES_FAILED错误type的codes:/*对于OFPET_TABLE_FEATURES_FAILED的ofp_error_msg“code”的值。Data至少包含请求失败的第一个字节*/enumofp_table_features_failed_code{OFPTFFC_BAD_TABLE=0,/*指定的流表不存在*/OFPTFFC_BAD_METADATA=1,/*无效的元数据的掩码*/OFPTFFC_BAD_TYPE=2,/*未知的属性类型.*/OFPTFFC_BAD_LEN=3,/*属性长度问题*/OFPTFFC_BAD_ARGUMENT=4,/*不支持的属性值*/OFPTFFC_EPERM=5,/*允许的错误*/};对于为OFPET_EXPERIMENTER错误type,错误信息由以下结构体和字段定义,后面跟着实验者定义的数据:/*OFPET_EXPERIMENTER:错误消息(数据通路->控制器)*/structofp_error_experimenter_msg{structofp_headerheader;uint16_ttype;/*ofpet_experimenter*/uint16_texp_type;/*实验者定义*/uint32_texperimenter;/实验者ID与ofp_experimenter_header中相同*/uint8_tdata[0];/*可变长度的数据。基于类型和代码解析。无填充*/};OFP_ASSERT(sizeof(structofp_error_experimenter_msg)==16);实验者字段是实验者ID,与ofp_experimenter结构体中的相同(见7.5.4)。7.5对称信息7.5.1HelloOFPT_HELLO消息由一OpenFlow头加一组可变尺寸hello元素。/*OFPT_HELLO.此消息包含零个或多个可变尺寸的元素。未知的元素类型必须忽略/跳过,允许未来的扩展*/structofp_hello{structofp_headerheader;/*hello元素列表*/structofp_hello_elem_headerelements[0];/*元素列表,0或更多*/};OFP_ASSERT(sizeof(structofp_hello)==8);Header字段中的version字段(见7.1)必须设置为发送者(见6.3.1)支持的最高OpenFlow协议版本。Elemnets字段是一组hello元素,包含连接进行初次握手时传递的可选数据。实现时必须忽略(跳过)Hello消息中不支持的所有元素。列表中的元素类型定义如下:/*Hello元素类型*/enumofp_hello_elem_type{OFPHET_VERSIONBITMAP=1,/*支持的版本位图*/};元素定义包含元素的类型,长度,和任何相关的数据:/*所有hello元素共同的头*/structofp_hello_elem_header{uint16_ttype;/*OFPHET_*之一*/uint16_tlength;/*在本单元的字节长度*/};OFP_ASSERT(sizeof(structofp_hello_elem_header)==4);OFPHET_VERSIONBITMAP元素使用下列结构和字段:

/*hello元素的版本位图*/structofp_hello_elem_versionbitmap{uint16_ttype;/*OFPHET_VERSIONBITMAP.*/uint16_tlength;/*在本元素的字节长度*//*其次是:包含位图的(长度-4)字节,然后(长度+7)/8×8-(长度)(0~7)的全零字节*/uint32_tbitmaps[0];/*位图列表-支持的版本*/};OFP_ASSERT(sizeof(structofp_hello_elem_versionbitmap)==4);Bitmaps字段表示设备支持的OpenFlow交换协议版本,可在版本协商后使用(见6.3.1)。对位图的比特通过协议的ofp_version数索引;如果左位移数值表示的比特等于设置的ofp_version,就支持这个OpenFlow版本。字段中包含的位图数值取决于支持的最高版本号:ofp_version0-31在第一个位图中编码,ofp_version32-63在第二个位图中编码,以此类推。例如,如果一个交换机只支持1.0版(ofp_version=0x01)和1.3版(ofp_version=0x04),第一个位图将被设置为0x00000012。7.5.2回送请求回送请求消息包括一个OpenFlow头加一个任意长度的数据字段。数据字段可能是一个消息的时间戳来检查延迟,不同长度来测量带宽,或零大小来验证交换机和控制器之间是否活跃。7.5.3回送答复回送应答消息包括一个OpenFlow头加上回声请求消息中未修改的数据字段。一个OpenFlow协议在实现时划分成多个层,回声请求/应答的逻辑应该在“最深”的开发层实现。例如,在OpenFlow的实现里,用户空间进程靠近内核模块,回声请求/应答是则在内核模块实现。接收一个格式正确的回应则表示端到端功能比在用户空间的进程中实现的回声请求/应答更可靠,同时也提供了更精确的端到端延迟时间。7.5.4实验者实验者消息的定义如下:/*实验者的扩展*/structofp_experimenter_header{structofp_headerheader;/*ofpt_experimenter*/uint32_texperimenter;/*实验者标识符*MSB0:低位字节由IEEEOUI定义。*MSB!=0:ONF定义的*/uint32_texp_type;/*实验者定义*//*实验者定义任意附加数据*/};OFP_ASSERT(sizeof(structofp_experimenter_header)==16);Experimenter的字段是一个32位的值,唯一标识实验者。如果最高位字节是零,接下来的三个字节是实验者的IEEEOUI。如果最高位字节不为零,这是一个ONF分配的值。如果实验者没有(或希望使用)他们的OUI,他们应该与ONF联系获得一个唯一的实验者标识符。标准的OpenFlow处理对其余部分不进行解析,可由实验者任意定义。如果一个交换机不理解实验者的扩充,它必须发送一个带有OFPBRC_BAD_EXPERIMENTER错误代码和OFPET_BAD_REQUEST错误类型的OFPT_ERROR消息。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- yrrf.cn 版权所有 赣ICP备2024042794号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务