table 中静态 LPM 条目的 P4 语法

P4 syntax for a static LPM entry in a table

这是一个关于 P4 语言的问题,该语言用于在网络中对数据平面进行编程。

假设我有以下简单的 header:

header ipv4_header_t {
    bit<8> ttl;
    bit<32> dst_addr;
}

struct headers_t {
    ipv4_header_t ipv4_header;
}

想象一下我有一个简单的 table 可以对目标地址进行最长前缀匹配 (LPM) 查找。

table ipv4_fib {
    key = {
        headers.ipv4_header.dst_addr: lpm;
    }
    actions = {
        act_miss;
        act_hit;
    }
    const default_action = act_miss();
}

向 table 添加一些静态 LPM 条目的 P4 语法是什么?

    entries = {
        ????: act_hit();    // Want entry for 0.0.0.0/0
        ????: act_hit();    // Want entry for 10.0.0.0/8
        ????: act_hit();    // Want entry for 10.1.2.3/32
    }

以下答案由 Vladimir Gurevich 提供,他在 P4 slack 频道的对话中回答了这个问题(参见讨论 https://p4-lang.slack.com/archives/C8ZR5EN3F/p1587830767153100

要将静态条目添加到最长前缀匹配 (lpm) table,您必须使用与三元条目相同的语法,使用 &&& 语法提供值和掩码:

table ipv4_fib {
    key = {
        headers.ipv4_header.dst_addr: lpm;
    }
    actions = {
        act_miss;
        act_hit;
    }
    const default_action = act_miss();
    const entries = {
        32w0x0a010203 &&& 32w0xffffffff: act_hit(1);   // 10.1.2.3/32 -> 1
        32w0x0a010200 &&& 32w0xffffff00: act_hit(2);   // 10.1.2.0/24 -> 2
        32w0x0a010000 &&& 32w0xffff0000: act_hit(3);   // 10.1.0.0/16 -> 3
        32w0x0a000000 &&& 32w0xff000000: act_hit(4);   // 10.0.0.0/8 -> 4
    }
}

最长前缀匹配可以被认为是三元匹配的特例,其中掩码由一系列连续的 1 (1) 和紧接着一系列连续的零 (0) 组成。

在某些(但不是所有)平台上,最长前缀匹配实际上是作为三元匹配实现的 "under the hood"。

注意 1:当您在 table 中提供静态条目时,条目必须是常量,因此软件不再可能向 [=35] 添加或从中删除动态条目=].由于 lpm tables 最常用于动态转发 tables,因此很少看到带有静态条目的 lpm table。

注意 2:我听说某些平台使用 lpm table 中条目的顺序作为匹配条目的优先顺序。因此,重要的是将更具体的整体(例如 10.1.0.0/16)放在不太具体的聚合条目(例如 10.0.0.0/8)之前。从技术上讲,这可以被认为是 "bug",因为在 lpm table 中,必须始终首选最长的前缀匹配。这种行为是由于在某些平台上 lpm table 实际上是作为三元 table 在后台实现的。我还被告知开源 v1model 确实匹配最长前缀(最具体)键,无论 table 中条目的顺序如何(即它没有 "bug")。

注意 3:如果您尝试添加带有全零掩码的默认条目(如下示例),您将收到错误消息(也在下面给出)。请改用 default_action。但是,table 中的默认条目和默认操作之间存在细微差别:在前一种情况下,table.apply() 将指示结果命中,而在后一种情况下,它将指示未命中。另一种方法是使用键 _。默认条目导致错误的事实可能被认为是一个错误,如果是这样,该错误可以在 P4 编译器的更高版本中修复:

    const entries = {
        32w0x0a010203 &&& 32w0xffffffff: act_hit(1);   // 10.1.2.3/32 -> 1
        32w0x0a000000 &&& 32w0xff000000: act_hit(2);   // 10.0.0.0/8 -> 2
        32w0x00000000 &&& 32w0x00000000: act_hit(3);   // 0.0.0.0/0 -> 3
    }
}

错误是:

$ p4c complex.p4
./complex.p4i(838): [--Werror=invalid] error: &&&: Invalid mask for LPM key
            32w0x00000000 &&& 32w0x00000000: act_hit(3); // 0.0.0.0/0 -> 3
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^