Programmable Packet Scheduling at Line Rate
目录
写在前面的话
可编程数据包调度使调度算法能够在不改变硬件的情况下在数据平面中进行编程,PIFO是目前的主要趋势。
PIFO
推入先出队列 (PIFO) 是一种优先级队列数据结构,它允许将数据包"推送"(排队)到队列中的任意位置,但仅从头部取消排队。PIFO支持可编程数据包调度:通过编程如何在每个数据包到达时计算PIFO中的位置,PIFO允许网络运营商表达各种实用调度器。此外,PIFO在硬件中以当今高端交换机典型的**高时钟速率(1 GHz)**是可行的。
动机
目前交换机调度程序是固定的。作为操作员,除了调整现有调度算法中的一些参数之外,一旦构建了交换机,就无法表达新的调度算法。
这种对交换机进行编程的功能在很多方面都很有用。它允许网络运营商通过为特定的应用程序目标运行特定的调度程序来自定义其网络。例如,"最短剩余处理时间"计划程序可最大限度地减少流完成时间,"公平排队"在争用流之间公平地共享受限制的链路容量,而最短的松弛时间可最大程度地减少尾部数据包延迟。
然而,尽管在模拟中显示出显著的优势,但这些调度程序在实践中尚未实现,因为无法修改现有交换机以支持新的调度程序。PIFO 旨在通过使交换机调度程序可编程来改变这种状况。
PIFO如何运作?
任何调度算法都会做出两个决定:数据包以什么顺序和何时传输?PIFO利用了这样的观察结果,即在许多实际的调度程序中,这些决策可以在数据包排队时做出。换句话说,数据包在调度顺序中的位置或其调度时间可以在排队时确定,利用已经缓冲的数据包的相对顺序不需要更改的事实。
这方面的一个例子是严格的优先级调度,其中每个数据包都有一个与之关联的优先级。使用此优先级,可以将数据包排队到维护调度顺序的数组中的正确位置。此外,已排队的数据包不需要相对于彼此重新排序。此排序数组是 PIFO,数据包的位置是通过编写程序来确定的,以便在每次数据包到达时对其进行计算。该程序计算数据包位置是使PIFO可编程的原因。
现在,有些算法确实需要随着新数据包到达而更改已缓冲数据包的相对顺序。一个例子是分层数据包公平排队(HPFQ),它以某种比例在类之间划分链路容量,然后在类内的流之间以某种比例递归,依此类推。但是,只需对 PIFO 稍作更改,即可将数据包或指针排队到另一个 PIFO,HPFQ 可以使用 PIFO 树实现。这种将PIFO组合在一起的能力非常强大,并允许我们类似地表达许多分层调度程序。
可编程性在于rank计算组件。在PIFO上下文中编程数据包调度算法是指编程如何计算每个数据包的rank。一个简单的例子是编程SRPT以最小化FCT,如图1所示。在这个例子中,数据包的rank只是流的剩余处理时间(或流的剩余字节)。请注意,SRPT要求终端主机将剩余的处理时间放在分组报头中的适当字段中,该字段与交换机中的数据包调度正交。给定这样的rank计算,PIFO队列将首先以最短的剩余处理时间调度数据包,即实现SRPT。
一个更复杂的例子是为加权公平性编程STFQ,如图1所示。在这个例子中,数据包的rank是STFQ中数据包的虚拟开始时间。虚拟开始时间计算为相同流的前一个数据包的虚拟时间和虚拟完成时间的最大值。虚拟时间保持所有流中最后一个出列数据包的虚拟开始时间。数据包的虚拟完成时间是数据包的虚拟开始时间加上数据包长度除以流量权重。给定这样的rank计算,PIFO队列将首先调度具有最小虚拟开始时间的分组,即实现STFQ。
除了这两个示例之外,已经证明PIFO可以支持广泛的数据包调度算法,例如最小松弛时间优先(Least-Slack Time-First)、服务曲线最早截止时间优先(SC-EDF,Service-Curve Earliest Deadline First)等。
PIFO表达什么?
1、优先级安排的变体(最早的截止日期优先、最不达到的服务等)
2、加权公平排队
3、分层数据包公平排队
4、令牌存储桶形式的流量整形(最大速率限制)
5、特定流的最小速率限制
PIFO不表达什么?
PIFO 无法表示算法,其中特定流的排队限制为特定的最大速率。虽然 PIFO 可以在数据包排队到 PIFO 之前表示最大流速限制,但它们在排队端不能这样做。
PIFO在硬件中的实用性如何?
在Verilog中实施了PIFO。硬件设计利用了这样一个事实,即大多数调度程序跨流而不是数据包进行调度。对于这些调度程序,数据包在 PIFO 中的优先级在流中单调增加。利用这一事实,我们仅对所有流的头数据包进行排序,并将剩余的数据包存储在先进先出队列 (FIFO) 组中。
我们的硬件实现是这些头数据包的排序数组。来自新流的传入数据包通过将其优先级与所有头数据包并行比较,然后移动阵列以容纳新数据包,将其插入正确的位置。当 PIFO 取消排队时,我们移出数组的顶部元素,从 FIFO 库中获取刚刚取消排队的流的下一个数据包,然后将下一个数据包插入到数组中。