在tofino数据平面上实现表的模拟

在tofino数据平面上实现表的模拟

实验目的

当需要在数据平面实现较为复杂的信息存储和更新时,经常产生在数据平面存放一张表的需求,例如对于多台感兴趣的交换机,希望记录并更新交换机的各项网络状态信息。从数据抽象上来说,以表的形式来记录是直观的,从使用速率来说,将信息存储在数据平面可以避免与控制平面交互所需的较大时延,更适用于时延敏感的任务。

实验环境

sde版本:bf-sde-9.10.0

实验过程与分析

在数据平面存储数据的载体主要包括寄存器(register)、计数器(counter)、用户定义的元数据(user-defined metadata)。由于用元数据难以直观地建立映射关系,而计数器在数据平面只能进行简单的计数操作,所以我们考虑用寄存器来实现表的模拟。

由于寄存器本身,是一个index对应一个value的,并没有直接满足表中一个key对应多个value的特征,所以考虑不同的使用方法。

  • 第一种尝试思路

一个直白的想法是通过对寄存器进行分段读写,在不同段存储不同的信息,例如设置长度64bit的寄存器,15:0位(即低16位)用于存放交换机ID。

但寄存器并不支持分段写入,当写入的位数长度不是32位,例如register_data[15:0] = 16w5;时,则会报错error: can only output entire 32-bit ALU output,若改为32位,例如register_data[31:0] = 32w5;,则会出现以下报错:

error: Wide operations not supported in stateful alu, will only operate on bottom 32 bits
  • 第二种尝试思路

由于寄存器虽然可以分段读取但不支持分段写入,所以无法将多组值存入单组寄存器中。因此,我们考虑用多组寄存器来模拟表。一个直白的想法是,为每个表项都设置一组寄存器,包括key和value,即表中的每一列对应一组寄存器,且相同行的表项对应同一个index。但是这需要在key和index之间建立联系,因为寄存器中存放的是index与value之间的对应关系

例如,下表是我们希望存储在数据平面的表:

switch id (key) info1 info2 info3
105 1 11 111
106 2 22 222
107 3 33 333

如果为每个表项设置一组寄存器,就是如下效果:

index switch id (key)
1 105
2 106
3 107
index info2
1 11
2 22
3 33

其他info的寄存器情况类似info2,这样似乎能够满足我们的需求。但分析之后发现,当一个来自某交换机的新数据包到达时,数据平面需要对key所在的那组寄存器进行遍历搜索,才能得到对应的index。具体地说,以交换机id为107的那行表项为例,当一个来自107交换机的数据包到达时,我们希望更新107交换机的对应info,就需要这行所对应的index,因此需要对key所在的寄存器组进行搜索,以得到107对应的index=3

但是,目前还没有一种可以在数据平面遍历寄存器的方法,当表中行数较多时,这个问题就更加明显。

  • 第三种尝试思路

由于寻找index是有挑战的,所以我们考虑直接将key化为index来使用。例如,我们感兴趣的交换机是相邻交换机,那么可以发现,交换机id与数据包的入端口也是一一对应的,因为每个端口只能有一个直接相连的实体。因此,我们可以直接将数据包的入端口作为index来使用,考虑到交换机中实际使用的是端口的D_P编号,所以需要扩大寄存器组的元素数量以涵盖D_P编号范围:

Register<bit<32>,bit<16>>(200, 0) info1;
Register<bit<32>,bit<16>>(200, 0) info2;
Register<bit<32>,bit<16>>(200, 0) info3;

使用时,直接将D_P编号作为index进行索引,即可更新对应行的表项。这个方案的缺点在于,为了使得index直接发挥key的功能而无需搜索,可能引入较多的未使用空间。

总结

从目前讨论的几个方案来看,在tofino数据平面实现表的模拟,需要能够在数据包中直接获取index的值,这可以通过某些转化来达成,虽然可能引入额外的空间开销。

posted @ 2023-05-21 16:50  瑞图恩灵  阅读(140)  评论(0编辑  收藏  举报