OpenFlow Switch Specification 1.3.0 (三)

时间:2022-03-05 08:44:42
六、OpenFlow 安全通道(OpenFlow Channel 

        OpenFlow 通道是连接每一个交换到控制器的接口。通过这个接口,控制器配置和管理交换机,从交换机接收事件,向交换机发送数据包。

        在数据层与 OpenFlow 通道之间,接口是特定实现的,然而 OpenFlow 通道消息(channel messages)必须被 OpenFlow 协议规范化。OpenFlow 通道通常利用 TLS加密,但是也可以直接运行在 TCP之上。

6.1 OpenFlow 协议总览

        OpenFlow 协议支持三种消息类型(message types):controller-to-switch,asynchronous 和 symmetric,每一种消息类型有多种子类型。 controller-to-switch 消息由控制器初始化,用来直接管理或监视交换机的状态。asynchronous 消息由交换机初始化,用来更新控制器的网络事件(network events)和记录的交换机状态。symmetric 消息可以被控制器或交换机初始化,并且在没有请求的情况下发送。OpenFlow 使用的消息类型接下来会描述。

6.1.1 controller-to-switch

        controller-to-switch 消息是由控制器初始化的,而且没有要求交换机收到消息后必须响应回复。

Features :控制器可能会询问交换机的能力(capabilities),这时交换机会发送 features 请求;交换机在收到这个请求后必须回复具有说明交换机的能力的特征信息。这个请求通常在建立 OpenFlow通道时执行。

Configuration :控制器可以设置(set)和查询(query)交换机的配置参数。交换机只回复来自控制器的查询。

Modify-State :Modify-State 消息是由控制器发送给交换机的,以此来管理交换机的状态。其最初的设计用意是:增加、删除和修改流表项和组表项(flow/group entries),以及设置端口的性能。

Read-State :Read-State 消息被控制器用来收集交换机的各种信息,例如当前配置(configuration),统计数据(statistics)和能力(capabilities)。

Packet-out :这个消息可以使交换机的指定端口发送数据包,可以用来转发来自“packet-in”消息的数据包。Packet-out 消息必须包含一个完整的数据包或者一个“buffer ID”,这个 ID 指向保存在交换机中的数据包。这个消息也必须包含一个动作列表,按动作列表中的先后顺序对数据包进行操作;空动作列表表示删除数据包。

Barrier:Barrier request/reply 消息是控制器用来保证“消息依赖”(message dependencies)已经满足,或者是用来通知控制器某个操作已经完成。

Role-Request:Role-Request 消息是交换机用来设定其 OpenFlow 通道角色的,或者用来查询这个角色。这个命令最有用的场合是交换机连接多个控制器的时候(见6.3.4章节)。

Asynchronous-Configuration:Asynchronous-Configuration 消息是控制器用来设置额外的“异步消息过滤器”的,通过此设定,OpenFlow通道可以接收它想要的异步消息。或者用此消息来查询这个以上设定的“过滤器”。这个消息在交换机连接多个控制器的情况下非常有用(见6.3.4章节),并且此消息通常在建立 OpenFlow 通道时执行。

6.1.2  Asynchronous

        异步消息的发送是不需要控制器先发请求的。交换机发送异步消息给控制器,为的是告诉控制器有数据包到来,或者是向控制器报错。四类主要的异步消息类型列于下文。

Packet-in:将数据包的控制权转交给控制器。对于所有的通过流表项或者 table-miss 流表项转发给 CONTROLLER 保留端口的数据包,总是会有一个“packet-in”事件发送到控制器(controllers)(见5.12)。其它的处理流程,例如 TTL 检查,也可能会用 “packet-in”事件发送数据包到交换机。

        “packet-in”事件可以被配置成 buffer packets。对于“流表项”或“组桶”(group bucket)的“output action”生成的 packet-in,可以由 output action 自己独立指定这个配置(见A.2.5),对于其它的 packet-in 则是由“交换机配置”来配置的(见A.3.2)。如果“packet-in”事件被配置成 buffer packets 并且交换机有足够的内部存储去缓存它们,那么 packet-in 事件只包含数据包中的一些包头片段和一个 buffer ID。这个 buffer ID ,通过此 ID 控制器可以用来转发这个数据包。如果交换机不支持 internal buffering,则相当于交换机被配置成不能为 packet-in 事件 buffer packets,或者内部存储不足,这种情况下,必须把完整的数据包作为此“事件”的部分发送给控制器。缓存的数据包通常通过一个来自控制器的 Packet-out 消息处理,或者由于自动超时处理。

        如果数据包被缓存,包含在“packet-in”消息中的“被缓存数据包”片段的字节数可以被配置。缺省条件下为128字节。 对于由“流表项”或“组桶”(group bucket)的“output action”生成的 packet-in,可以由 output action 自己独立指定这个值(见A.2.5),对于其它的 packet-in 则是由“交换机配置”来配置的(见A.3.2)
Flow-Removed:通知控制器有流表项从流表中删除。只有设置了 OFPFF_SEND_FLOW_REM 标记(flag)的“流表项”在删除时才会发送 Flow-Removed 消息。生成这种消息,一来,作为控制器“删除流表项”请求完成情况的响应信息;二来,用作流表项超时,交换机将其删除,向控制器发送的通知。

Port-status:通知控制器交换机的端口状态有变化。交换机在端口配置或端口状态发生改变时,应该向控制器发送 Port-status 消息。产生这个消息的事件有:“端口配置改变”,例如,端口被用户降低(it was brought down directly by a user);“端口状态改变”,例如链路断开。

Error:交换机通过 error 消息通知控制器出现问题(或故障)。

6.1.3  Symmetric

        对称消息是不经请求而发送的双向消息。

Hello:当建立连接时,在控制器和交换机之间交换 Hello 消息。

Echo:Echo request 消息可以从交换机发出,也可以从控制器发出,收到此消息后必须以 Echo reply 消息回复。此消息用以验证 controller-switch 连接存在,也可用来测量此连接的延时及带宽。

Experimenter:experimenter 消息为交换机提供一个标准的方式,用以在 OpenFlow 现有消息类型范围外,添加额外的功能。这也是为将来的 OpenFlow 修订设计的筹划区域。

6.2 消息处理

        OpenFlow 协议提供了可靠的消息递送和处理流程,但是自身并没有提供 “确认”或“保证”消息的处理的顺序。这一章节描述的 OpenFlow 消息处理行为适用于“主连接”(main connections)和 基于可靠通信的辅助连接(auxiliary connections),而对于不可靠通信的辅助连接,并不适用(见6.3.5章节)。

         消息递送(Message Delivery):消息保证是可递送的,除非 OpenFlow 通道完全失效,在这种情况下,控制器不能假设交换机的任何状态(例如,交换机可能进入了“失败孤立模式”)。

         消息处理流程(Message Processing):交换机必须处理来自控制器的全部消息,必要时还需要做出回应。如果交换机不能完全处理来自控制器的消息,交换机就必须返回一个 error 消息。对于 packet-out 消息,虽完全处理了这个消息,但并不能保证交换机发出了指定的数据包。指定的数据包可能由于“交换机拥塞”、“Qos策略”,被 OpenFlow 处理流程悄无声息地删掉;或者是指定数据包被发送到了阻塞的或者非法的端口。

        另外,交换机必须向控制器发送所有生成的 asynchronous 消息。当交换机的 OpenFlow 状态发生改变,如 flow-removed,port-status 或者收到 packet-in 消息时,便会产生异步消息,这样才能保证控制器记录的“交换机视图”与“实际交换机状态”一致。这些 asynchronous 消息可能会根据“异步配置”(asynchronous configuration)(见6.1.1)被过滤掉。另外,触发 OpenFlow 状态改变的条件可能在造成此改变前就被过滤掉(也就是说,硬件上状态改变了,但是在交换机的 OpenFlow 软件状态上并未发觉)。例如,交换机端口收到的数据包本应该转发给控制器,却因为“拥挤”或 QoS策略被删除掉,这样就不能生成“packet-in”消息。这种“删除”可能发生在那些被控制器 output action 明确指定的数据包。这种“删除”也可能发生在数据包不能匹配流表中的任何流表项,而表的“default action” 是将数据包发送到控制器。向控制器发送数据包的策略建议使用 “QoS 动作”(QoS actions)或者“流量限制”(rate limiting),如此来避免向控制器连接发起拒绝服务攻击,这些已经超出了当前说明书的讨论范围。

        控制器可以*忽视接收到的消息  ,但是必须响应 echo 消息,如此来避免交换机切断连接。

         消息顺序(Message Ordering):消息的执行顺序可由 barrier 消息来保证。在没有barrier messages 的时候,交换机可能会任意重排消息执行的顺序,以提高处理性能;因此,控制器不应当依赖于特定的处理顺序。特别是,流表项插入表中的顺序可能会与交换机收到的“flow mod messages”指定的顺序不同。通过 barrier message,消息肯定不会被重排,而且 barrier message 肯定会在所有的前置消息完成后才处理。更加精确地描述见下:

1. barrier 消息之前的消息必须全部完成,包括发送 resulting reply 或者errors
2. barrier 消息必须随后处理,然后发送 barrier reply
3. barrier 之后的消息开始执行

        如果有两个消息彼此依赖(例如,一个 flow mod 向 OFPP_TABLE 添加了一个 packet-out )(e.g. a flow mod add with a following packet-out to OFPP_TABLE),它们应当被 barrier message 分开。

6.3 OpenFlow 通道连接

        OpenFlow 通道是用来在 OpenFlow 交换机和 OpenFlow 控制器之间交换OpenFlow 消息的。一个典型的 OpenFlow 控制器管理着多个 OpenFlow 通道,每一个通道连接着一个不同的交换机。一个 OpenFlow 交换机可能有一个 OpenFlow 通道,仅连着一个控制器;也可能出于可靠性考虑,有多个通道,每一个通道连着不同的控制器(见6.3.4)。

        典型地,一个 OpenFlow 控制器跨越一个或多个网络(networks)来远程管理一个 OpenFlow 交换机。对于 OpenFlow 通道使用的网络的说明已经超出了本说明文档的讨论范围。此网络可以是一个分离的专用网络,或者是一个 OpenFlow 交换机管理着的网络(即 in-band 控制器连接)。唯一的需求是,必须提供 TCP/IP 连接。

        OpenFlow 通道通常被初始化为一个单一的网络连接,使用 TLS 或者纯粹的 TCP(见6.3.3)。OpenFlow 通道可能是由多个并行的网络连接构成的(见6.3.5)。OpenFlow 交换机通常向 OpenFlow 控制器发起连接(见6.3.1)。

6.3.1  连接 建立

        交换机必须与控制器建立通信。交换机需要用户配置的(user-configurable)(或者固定的)IP 地址,以及用户指定的端口。如果交换机知道控制器的 IP 地址,交换机就会向控制器发起标准的 TLS 或 TCP 连接。此时,在 OpenFlow 通道中交互的流量都不通过 OpenFlow 管线。因此,交换机必须在流表可用前,识别到来的流量,并做本地处理。

        当一个 OpenFlow 连接初步建立,连接的两端必须立即发送 OFPT_HELLO 消息,附带自身可支持的最高版 OpenFlow 协议版本号字段。基于此,两端选择均可支持的最小协议版本。

        如果协商版本彼此支持,则建立连接成功。否则,版本不能支持的一方需要回复一个“OFPT_ERROR”消息,此消息中需有“OFPET_HELLO_FAILED”类型字段,“OFPHFC_COMPATIBLE”代码字段,以及在 data 中置入可选的、用来说明具体情况的ASCII字符串信息。最后中断连接。

6.3.2  连接中断

        这种情况的发生,是交换机与所有的控制器失去了连接,其表现就是 echo 请求超时,TLS 会话超时,或者其它的断连情况。此时,交换机应当立即进入“失败安全模式”(fail secure mode)或者“失败孤立模式”(fail standalone mode),这完全依赖于交换机的实施与配置。在“失败安全模式”下,唯一的交换机行为唯一的变化就是,发往控制器的消息及数据包均删除。流表项照常匹配,超时则删除。在“失败孤立模式”中,交换机使用 OFPP_NORMAL 保留端口处理所有的数据包;换句话说,就是 OF 交换机的行为与旧的 Ethernet 交换机或路由器行为一致。“失败孤立模式”通常只能发生在 hybrid switches 上。

        一旦再次连接上控制器,交换机会有遗留的流表项保存。此时,控制器可以选择将所有的流表都删掉。

        交换机首次启动,它将运行在“ 失败安全模式”或者“ 失败孤立模式”,直到成功地连接上控制器。启动时配置的缺省流表项超出了 OpenFlow 协议的讨论范围。

6.3.3  加密

        交换机和控制器可能是通过 TLS 连接 通信的。TLS 连接是由交换机在启动的候向控制器发起的,其缺省的 TCP 端口是 6633。交换机和控制器相互验证经私钥签名过的证书。交换机必须由用户配置一份证书,用以验证;同时控制器必须可以认证控制器(交换机证书)。

        交换机和控制器可选择使用存粹的 TCP 连接建立通信。当使用 纯粹的 TCP,建议使用备选的安全措施,以防窃听、控制器模拟器或者其它 OpenFlow 通道上的攻击。

6.3.4  多控制器

        交换机可与一个控制器建立连接,也可与多个控制器建立连接。当与多个控制器建立连接后可以增强可靠性,因为当与一个控制器连接失败后,交换机仍可继续工作在 OpenFlow 模式下。 控制器对交换机管理权的移交完全是由控制器自己管理的,这样做的好处是允许快速失败恢复”,并且有利于控制器的负载均衡。控制器(controllers)之间通过什么机制,如何协调管理交换机超出了本说明的讨论范围。多控制器的优点,只有在控制器之间切换时状态保持同步时才起作用。多控制器旨在处理控制器的“失败恢复”和控制器的“负载均衡”,并不是解决虚拟化,虚拟化的内容超出了 OpenFlow 协议(说明)。

        当 OpenFlow 操作被初始化,交换机必须与所有配置的控制器相连,并且尽力地同时地维持所有连接。多个控制器可能会发送 controller-to-switch 命令到交换机,那么交换机就需要向相应的控制器回复。异步消息也可能需要发送到多个控制器,将消息复制多份,发给每一个合法的并愿意接收此消息的 OpenFlow 通道。

        控制器缺省的角色是 OFPCR_ROLE_EQUAL,控制器对交换机有完全的访问权,并且每一个交换机在角色上都是平等的。缺省的条件下,交换机接收所有的 Asynchronous messages(例如 packet-in,flow-removed)。控制器可以发送 controller-to-switch 命令去修改交换机的状态。交换机并不会给两个控制器之间做任何仲裁或资源共享。

        控制器可以请求使自己的角色改为 OFPCR_ROLE_SLAVE。在这种角色下,控制器对交换机只有 read-only 访问权限。缺省条件下,控制器不接收除 Port-status 消息以外的交换机 Asynchronous messages。交换机此时也禁止了执行 controller-to-switch 命令的能力,不能再修改交换机的状态;也禁止了 OFPT_PACKET_OUT、OFPT_FLOW_MOD、OFPT_GROUP_MOD、OFPT_PORT_MOD 和 OFPT_TABLE_MOD。如果控制器发送了那些命令,交换机必须回复以 OFPT_ERROR 消息,消息的类型字段为 OFPET_BAD_REQUEST,代码字段为 OFPBRC_IS_SLAVE。其余的 controller-to-switch 消息,如 OFPT_MULTIPART_REQUEST 和 OFPT_ROLE_REQUEST,应该正常处理。

        控制器可以请求使自己的角色变为 OFPCR_ROLE_MASTER。这个角色与 OFPCR_ROLE_EQUAL相似,对交换机有完全的访问权,其不同之处是,交换机确保它是唯一的控制器。当一个控制器把自己的角色改为 OFPCR_ROLE_MASTER ,交换机就把其它的具有 OFPCR_ROLE_MASTER 角色的控制器改为 OFPCR_ROLE_SLAVE。当交换机执行这种角色改变操作时,交换机将不再为角色被改变的控制器发送消息(多数情况下,控制器将不再可访问)。

        一个交换机可能同时与多个处于同等地位的控制器相连。多个控制器处于 Slave 状态,至多一个控制器处于 Master 状态。每一个控制器都会通过一个 OFPT_ROLE_REQUEST 消息与交换机交流它的角色,并且交换机必须记住每一个连接的控制器的角色。控制器可能在任何时刻改变自己角色。

        一个控制器也可以控制让哪些交换机的 asynchronous messages 通过自己的 OpenFlow 通道,改变以上描述的缺省配置。以上那些改变都是通过一个  Asynchronous Configuration  message(见6.1.1章节)实现的,在附录 A.3.10 部分列出了 OpenFlow 通道的哪些消息类型必须要以及哪些消息可以过滤掉的原因(见A.3.10)。利用这个特性,不同控制器可以收到不同的通知,一个“主控制器”可以选择性地禁止它不关心的消息,而一个“从控制器”可以选择想要监控的消息。

        为了检测 master/slave 转换过程中消息的乱序, OFPT_ROLE_REQUEST 消息包含一个64位的序列号字段,generation_id,用来区分主从关系视图( identifies a given mastership view )。作为选择 master 机制的一部分,控制器(或者第三方代表)协调 generation_id 的赋值。generation_id 是一个递增的计数器:每当主从关系视图(mastership view)改变,一个新的(更大的)generation_id 被赋值,例如,当一个新的 master 被指定。generation_id 可以循环增长。

        当收到 OFPT_ROLE_REQUEST 消息,其角色等于 OFPCR_ROLE_MASTER 或者 OFPCR_ROLE_SLAVE。交换机必须比较消息中的 generation_id 和它目前看到过的最大 grneration_id。如若消息中的 grneration_id 小于目前看到过的 grneration_id,则此消息被被认为是旧消息(stale),将其抛弃。交换机必须回复此旧消息(stale messages) 以 error 消息,error 消息的类型为 OFPET_ROLE_REQUEST_FAILED,代码为 OFPRRFC_STALE。

        下面的伪代码描述了交换机处理  grneration_id 的行为。

On switch startup:
    generation_is_defined = false;

On receiving OFPT_ROLE_REQUEST with role equal to OFPCR_ROLE_MASTER or OFPCR_ROLE_SLAVE
and with a given generation_id, say GEN_ID_X:

    if (generation_is_defined AND
    distance(GEN_ID_X, cached_generation_id) < 0) {
        <discard OFPT_ROLE_REQUEST message>;
        <send an error message with code OFPRRFC_STALE>;
    } else {
        cached_generation_id = GEN_ID_X;
        generation_is_defined = true;
        <process the message normally>;
    }
    where distance() is the Wrapping Sequence Number Distance operator defined as following: 
    distance(a, b) := (int64_t)(a - b)

        也就是说,distance()是一个无符号的序列号之间的不同,当a比b大时会产生(在循环增长的数的情况下)一个正 distance,但是这个 distance 小于“序列号空间的一半”。相反地情况会生成一个负数(a < b)。

        交换机必须忽视角色为 OFPCR_ROLE_EQUAL 的 OFPT_ROLE_REQUEST消息中的 generation_id,因为 generation_id 是专门为了明确 master/slave转变的竞争条件。

6.3.5 辅助连接

        缺省情况下,OF 交换机与 OF 控制器之间的 OpenFlow 通道是一个单一的网络连接。OpenFlow 通道也可以是由 主连接(main connection) 和多个辅助连接(auxiliary connections)。辅助连接是由 OF 控制器创建的,可以增强交换机的处理性能,显露多数交换机的并行处理接口。

        每一个连到控制器的交换机连接,被标识为交换机 Datapath ID 和一个  Auxiliary ID(见A.3.1)。主连接的  Auxiliary  ID 被设为 0 , 而辅助连接的 Auxiliary ID 必须为非 0 ,Datapath ID 与主连接相同。辅助连接必须使用与主连接相同的 source IP address,但是可以使用不同的端口号,例如,TLS、TCP、DTLS 或者 UDP,这些都是根据交换机的配置而定的。辅助连接必须有和主连接一样的目的 IP 和目的端口号,除非交换机的配置信息指定了其它配置。控制器必须识别带有非 0 Auxiliary ID 的连接,并且将这些连接绑定到与主连接同样 Datapath ID 上。

        交换机在启动附加连接之前必须完成主连接的启动(见6.3.1章节),交换机只有在主连接存活时才 维持辅助连接。辅助连接的建立与主连接的建立使相同的(见6.3.1章节)。当交换机发现主连接断开,它应该立即把所有与控制器连接的辅助连接关掉,以使控制器可以正确处理 Datapath ID 冲突。

        OpenFlow 交换机和 OpenFlow 控制器的所有连接,必须都可以接收任何的 OpenFlow 消息类型和子类型:主连接和辅助连接不应该在接收消息上有区别。然而,对于不同的连接,处理不同消息类型的性能是由区别的。辅助连接使用 DTLS 和 UDP,会有丢失或重排消息的可能,而 OpenFlow 并没有为这些连接提供排序和转发保证(见6.2章节)。因此, 必须在消息到来的连接上回复 OpenFlow 请求,因为各连接直接没有同步机制,来自不同连接的消息会以任意的顺序处理。一个 barriermessage 只应用到需要它的连接上(见6.2章节)。如果消息必须顺序处理,它们必须被发送到相同的连接上,使用一个不会重排数据包的连接,并使用 barrier messages。

        控制器可以根据它自己的判定,选择任意的连接去发送 OpenFlow 消息,然而为了使多数交换机得到最好的执行效率,下列的条例需要采纳:

*所有的非 Packet-out 控制器消息(flow-mod,statistic request…)应该发送到主连接。
*所有的带有来自 Packet-In 消息的数据包的 Packet-out 消息,应该发送到 Packet-In 消息到来时的连接。
*所有的其它类型的 Packet-Out 消息可以分散给各个辅助连接,此时需要一种机制,维持数据包和连接之间的映射。
*如果打算使用的辅助连接不可用,则控制器应该使用主连接。

        交换机也可以按照自己的意愿,*地使用多种连接来发送 OpenFlow 消息,但是需要遵守下面的条例:

*所有的非 Packet-In 消息应当通过主连接发送。
*所有的 Packet-In 消息 可以分散给各个辅助连接,此时需要一种机制,维持数据包和连接之间的映射。

6.4 流表修改消息

        流表修改消息由以下的类型:

enum ofp_flow_mod_command  {
    OFPFC_ADD = 0, /* New flow. */
    OFPFC_MODIFY = 1, /* Modify all matching flows. */
    OFPFC_MODIFY_STRICT = 2, /* Modify entry strictly matching wildcards and priority. */
    OFPFC_DELETE = 3, /* Delete all matching flows. */

    OFPFC_DELETE_STRICT = 4, /* Delete entry strictly matching wildcards and priority. */
};

6.5 组表修改消息

        组表修改消息有以下的类型:

/* Group commands */
enum ofp_group_mod_command {
    OFPGC_ADD = 0, /* New group. */
    OFPGC_MODIFY = 1, /* Modify all matching groups. */
    OFPGC_DELETE = 2, /* Delete all matching groups. */
};

6.6 计量器修改消息

        计量器修改消息有以下的类型:

/* Meter commands */
enum ofp_meter_mod_command {
    OFPMC_ADD, /* New meter. */
    OFPMC_MODIFY, /* Modify specified meter. */
    OFPMC_DELETE, /* Delete specified meter. */
};