OpenvSwitch代码阅读笔记(1)-- Freezing Translation

前言

最近几个月的工作主要是对Open vSwitch的Windows Server版进行功能扩展。在阅读代码过程中,在ovs-vswitchd处理数据平面的请求时,遇到frozen_state字段,今天在阅读Openflow流表转换的代码时,看到关于冻结转换的注释(ofproto-dpif-xflate.c:273 - 378),特此翻译如下。

冻结转换 (Freezing Translation)

在转换的过程中,会遇到需要暂停并设置一个检查点的情况,这样,转换操作可以在以后重新开始。设置checkpoint的过程被称为“freezing”,而重启该操作的过程被称为“thawing”。

freezing的使用场景:

  1. “Recirculation”, 转换操作发现在不执行以完成的转换的情况下,它没有足够的信息完成剩余的转换操作。在这种情况下,转换操作被冻结(freeze)并且相应的数据被赋予一个唯一的“recirculation ID”,该值被保存在用户空间的一个表中(参见ofproto-dpif-rid.h)。同时,添加一个OVS_ACTION_ATTR_RECIRC的动作,该动作的值是“recirculation ID”。当一个数据报触发这个动作后,数据平面使用该ID重新查表。如果,数据平面没有找到对应的记录,数据平面将请求控制平面处理。控制平面从“recirculation table”中查到ID,如果此时相关的信息已知,就重启转换操作。
    原生的例子是MPLS。MPLS在Openflow中的实现,只有在最后一个MPLS标签后面的协议被剥离后,才能知道数据报封装的具体的协议。就是说,OVS无法跳过MPLS标签直接解析数据帧头。因此,在这种情况下,通过“recirculation”操作解析MPLS封装的数据帧。
    (OVS同时使用OVS_ACTION_ATTR_RECIRC来实现输出到绑定网卡的哈希操作。OVS预先生成所有在数据平面上输出到绑定网卡上的流表,因此,将数据报发给用户空间做再一次转换这样复杂的流程就不需要了,即,绑定网卡不会按照上面提到的过程来处理。)

  2. “Continuation”。A continuation是Openflow控制器干预数据报处理的一种机制。当转换过程中遇到一个带有“pause”标记的“controller”操作,转换就被暂停,被冻结的数据经过序列化后,发送给Openflow的控制器。控制器然后检查或修改被冻结的数据,并最终将数据发送给虚拟交换机,然后虚拟交换机解冻这些数据并继续转换操作。

冻结转换的主要问题时保存状态,因此当转换被解冻时,操作能够继续进行而没有被破坏。尤其是,动作必须按照下面的顺序保存:

  • 如果冻结转换的原因是需要更多的信息,指明冻结原因的操作。
  • 任何其他的在当前流表中等待执行的操作。
  • 如果转换在NXAST_RESUMIT中被冻结,任何其他的操作都在resubmit操作的后面。resubmit操作可能是嵌套的,所以必须返回到控制平面处理。
  • Openflow 1.1+中定义的操作集合。

动作或流表查询所依赖的状态,必须保存,例如:

  • 元数据字段(输入端口,寄存器,OF1.1+的元数据,… )
  • NXAST_STACK_PUSH和NXAST_STACK_POP操作使用的栈信息
  • 在控制平面栈的每个级别上,流表的表ID和cookie被转换,因为它们在执行OFPAT_CONTROLLER操作(包括其他的方式)时是可见的。

通过这些字段,转换控制状态的保存。当一个冻结转换被识别时,转化过程如下:

  1. 设置‘freezing’为true。
  2. 设置‘exit’为true,这样后续的操作就会知道上一个操作从转换过程中推出。
  3. 在‘frozen_actions’中添加OFPACT_UNROLL_XLATE动作,并且为了以后能够很方便的找到当前的操作,frozen_actions.header指向这个动作。这个动作中保存了当前的表ID和cookie,所以在后续的环回的转换中,它们能被恢复过来。
  4. 添加指示环回的动作,以及流表中其他后续的动作到’frozen_actions’中,这样,它们就能被执行当该流表重新被执行转换时。
  5. 返回。
  6. 指示环回的动作也许被嵌套在被重新提交的请求中,该请求还有没有执行的动作。所有这些都表明,当前离开和冻结了动作,并且在‘frozen_actions’中再次添加OFPACT_UNROLL_XLATE动作,以及没有被执行的动作。

如果因为环回冻结转换,调用者生成一个环回ID,并且保存所有的当前操作的状态。对于所有的环回转换,调用者把它们传递新的转换去执行。这个过程中,产生了一组可以被直接转换的ofpacks,这时,它们的处理就没什么特殊之处了。