Devlink DPIPE¶
背景¶
在执行硬件卸载过程中,许多硬件的细节无法呈现。这些细节对于调试非常有用,devlink-dpipe
提供了一种标准化的方式来提供对卸载过程的可见性。
例如,Linux内核使用的路由最长前缀匹配(LPM)算法可能与硬件实现不同。管道调试API(DPIPE)旨在以通用方式为用户提供对ASIC管道的可见性。
硬件卸载过程应该以用户无法区分硬件与软件实现的方式完成。在这个过程中,硬件的细节被忽略了。实际上,这些细节可能有很多含义,并且应该以某种标准的方式公开。
当一个人希望将整个网络堆栈的控制路径卸载到交换机ASIC时,这个问题会变得更加复杂。由于硬件和软件模型的差异,某些过程无法正确表示。
一个例子是内核的LPM算法,在许多情况下,它与硬件实现大相径庭。配置API是相同的,但是不能依赖转发信息库(FIB)看起来像硬件中的分层路径压缩树(LPC-trie)。
在许多情况下,仅基于内核的转储来分析系统故障可能不够。通过将这些数据与有关底层硬件的补充信息相结合,可以使调试更容易;此外,该信息在调试性能问题时也很有用。
概述¶
devlink-dpipe
接口弥补了这一差距。硬件的管道被建模为匹配/操作表的图形。每个表代表一个特定的硬件块。这个模型并不新鲜,最初由P4语言使用。
传统上,它被用作硬件配置的替代模型,但是 devlink-dpipe
接口将其用作可见性的标准补充工具。从devlink-dpipe
看到的系统视图应该根据标准配置工具所做的更改而改变。
例如,使用三态内容寻址存储器(TCAM)来实现访问控制列表(ACL)是很常见的。TCAM存储器可以分为TCAM区域。复杂的TC过滤器可以具有多个具有不同优先级和不同查找键的规则。另一方面,硬件TCAM区域具有预定义的查找键。使用TCAM引擎卸载TC过滤器规则可能导致多个TCAM区域以链式方式互连(这可能会影响数据路径延迟)。为了响应新的TC过滤器,应该创建描述这些区域的新表。
模型¶
DPIPE
模型引入了几个对象
头
表
条目
header
描述数据包格式,并提供数据包中字段的名称。table
描述硬件块。entry
描述特定表的实际内容。
硬件管道不是端口特定的,而是描述整个ASIC。因此,它与 devlink
基础设施的顶部相关联。
驱动程序可以在运行时注册和注销表,以支持动态行为。这种动态行为对于描述可以动态分配和释放的TCAM区域等硬件块是强制性的。
devlink-dpipe
通常不用于配置。例外情况是特定表的硬件计数。
以下命令用于从用户空间获取 dpipe
对象
table_get
:接收表的描述。
headers_get
:接收设备支持的头。
entries_get
:接收表的当前条目。
counters_set
:启用或禁用表上的计数器。
表¶
驱动程序应为每个表实现以下操作
matches_dump
:转储支持的匹配项。
actions_dump
:转储支持的操作。
entries_dump
:转储表的实际内容。
counters_set_update
:同步硬件,启用或禁用计数器。
头/字段¶
与 P4 类似,头和字段用于描述表的行为。标准协议头和特定的ASIC元数据之间存在细微差异。协议头应在 devlink
核心API中声明。另一方面,ASIC元数据是驱动程序特定的,应在驱动程序中定义。此外,每个驱动程序特定的devlink文档文件都应记录驱动程序特定的 dpipe
头。头和字段通过枚举来识别。
为了提供进一步的可见性,一些ASIC元数据字段可以映射到内核对象。例如,内部路由器接口索引可以直接映射到网络设备ifindex。不同虚拟路由和转发(VRF)表使用的FIB表索引可以映射到内部路由表索引。
匹配¶
匹配保持原始状态,并且接近硬件操作。由于这正是我们希望详细描述的过程,因此不支持LPM之类的匹配类型。匹配示例
field_exact
:对特定字段进行精确匹配。
field_exact_mask
:在屏蔽后对特定字段进行精确匹配。
field_range
:匹配特定范围。
应指定头和字段的 ID,以便识别特定字段。此外,应指定头索引,以便区分数据包中同一类型的多个头(隧道)。
操作¶
与匹配类似,操作保持原始状态,并且接近硬件操作。例如
field_modify
:修改字段值。
field_inc
:增加字段值。
push_header
:添加一个头。
pop_header
:删除一个头。
条目¶
可以按需转储特定表的条目。每个条目都用索引标识,其属性由匹配/操作值列表和特定计数器描述。通过转储表内容,可以解决表之间的交互。
抽象示例¶
以下是Mellanox Spectrum ASIC的L3部分的抽象模型示例。这些块按照它们在管道中出现的顺序进行描述。以下示例中的表大小不是真实的硬件大小,仅用于演示目的。
LPM¶
LPM算法可以实现为哈希表列表。每个哈希表都包含具有相同前缀长度的路由。列表的根是/32,如果未命中,则硬件将继续到下一个哈希表。搜索的深度将影响数据路径延迟。
如果命中,则该条目包含有关管道下一阶段的信息,该阶段解析MAC地址。下一阶段可以是直接连接路由的本地主机表,也可以是下一跳的邻接表。meta.lpm_prefix
字段用于连接两个LPM表。
table lpm_prefix_16 {
size: 4096,
counters_enabled: true,
match: { meta.vr_id: exact,
ipv4.dst_addr: exact_mask,
ipv6.dst_addr: exact_mask,
meta.lpm_prefix: exact },
action: { meta.adj_index: set,
meta.adj_group_size: set,
meta.rif_port: set,
meta.lpm_prefix: set },
}
本地主机¶
对于本地路由,LPM查找已经解析了出口路由器接口(RIF),但是确切的MAC地址是未知的。本地主机表是将输出接口ID与目标IP地址组合作为键的哈希表。结果是MAC地址。
table local_host {
size: 4096,
counters_enabled: true,
match: { meta.rif_port: exact,
ipv4.dst_addr: exact},
action: { ethernet.daddr: set }
}
邻接¶
对于远程路由,此表执行ECMP。LPM查找会产生ECMP组大小和索引,该索引用作此表的全局偏移量。同时,会生成数据包的哈希值。基于ECMP组大小和数据包的哈希值,生成局部偏移量。多个LPM条目可以指向同一个邻接组。
table adjacency {
size: 4096,
counters_enabled: true,
match: { meta.adj_index: exact,
meta.adj_group_size: exact,
meta.packet_hash_index: exact },
action: { ethernet.daddr: set,
meta.erif: set }
}
ERIF¶
如果出口RIF和目标MAC已通过前面的表解析,则此表将执行多项操作,例如TTL减少和MTU检查。然后,会根据数据包的类型(广播、单播、多播)做出转发/丢弃的决定,并更新端口L3统计信息。
table erif {
size: 800,
counters_enabled: true,
match: { meta.rif_port: exact,
meta.is_l3_unicast: exact,
meta.is_l3_broadcast: exact,
meta.is_l3_multicast, exact },
action: { meta.l3_drop: set,
meta.l3_forward: set }
}