Skip to content

Commit

Permalink
[SAIP4] Model tunnel termination (aka decap). (sonic-net#283)
Browse files Browse the repository at this point in the history
* [p4_symbolic]:Initial inport of Ir Table entries and test Code. (sonic-net#287)

Co-authored-by: bhagatgit <115375369+bhagatgit@users.noreply.github.com>

* [SAIP4] Add ACL ingress security table to Middleblock and update match fields for ToR.
Reserve 2 entries in the VRF bank.

* Limit ToR ACL pre-ingress table to 127 entries.

* [SAI P4] Model tunnel termination (aka decap).

---------

Co-authored-by: VSuryaprasad-hcl <159443973+VSuryaprasad-HCL@users.noreply.github.com>
Co-authored-by: bhagatgit <115375369+bhagatgit@users.noreply.github.com>
Co-authored-by: jonathan-dilorenzo <dilo@google.com>
Co-authored-by: smolkaj <smolkaj@google.com>
  • Loading branch information
5 people authored Jul 8, 2024
1 parent 0907a44 commit abd606e
Show file tree
Hide file tree
Showing 21 changed files with 645 additions and 20 deletions.
1 change: 1 addition & 0 deletions sai_p4/fixed/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ filegroup(
"parser.p4",
"roles.h",
"routing.p4",
"tunnel_termination.p4",
"vlan.p4",
],
)
Expand Down
2 changes: 2 additions & 0 deletions sai_p4/fixed/headers.p4
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#define ETHERTYPE_ARP 0x0806
#define ETHERTYPE_LLDP 0x88cc

#define IP_PROTOCOL_IPV4 0x04
#define IP_PROTOCOL_TCP 0x06
#define IP_PROTOCOL_UDP 0x11
#define IP_PROTOCOL_ICMP 0x01
#define IP_PROTOCOL_ICMPV6 0x3a
#define IP_PROTOCOL_IPV6 0x29
#define IP_PROTOCOLS_GRE 0x2f

#define GRE_PROTOCOL_ERSPAN 0x88be
Expand Down
7 changes: 5 additions & 2 deletions sai_p4/fixed/ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#define L3_ADMIT_TABLE_ID 0x02000047 // 33554503
#define MIRROR_PORT_TO_PRE_SESSION_TABLE_ID 0x02000048 // 33554504
#define ECMP_HASHING_TABLE_ID 0x02000049 // 33554505
#define ROUTING_TUNNEL_TABLE_ID 0x02000050 // 33554506
#define ROUTING_TUNNEL_TABLE_ID 0x02000050 // 33554512
#define IPV6_TUNNEL_TERMINATION_TABLE_ID 0x0200004B // 33554507
// Next available table id: 0x0200004C (33554508)

// --- Actions -----------------------------------------------------------------

Expand All @@ -49,7 +51,8 @@
#define COMPUTE_LAG_HASH_IPV6_ACTION_ID 0x0100000E // 16777230
#define TRAP_ACTION_ID 0x0100000F // 16777231
#define ROUTING_SET_METADATA_AND_DROP_ACTION_ID 0x01000015 // 16777237
// Next available action id: 0x01000016 (16777238)
#define MARK_FOR_TUNNEL_DECAP_AND_SET_VRF_ACTION_ID 0x01000016 // 16777238
// Next available action id: 0x01000017 (16777239)

// --- Action Profiles and Selectors (8 most significant bits = 0x11) ----------
// This value should ideally be 0x11000001, but we currently have this value for
Expand Down
21 changes: 14 additions & 7 deletions sai_p4/fixed/metadata.p4
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ struct headers_t {

ipv4_t ipv4;
ipv6_t ipv6;

// Inner IP-in-IP headers.
ipv4_t inner_ipv4;
ipv6_t inner_ipv6;

icmp_t icmp;
tcp_t tcp;
udp_t udp;
Expand All @@ -170,7 +175,7 @@ struct headers_t {

// Header fields rewritten by the ingress pipeline. Rewrites are computed and
// stored in this struct, but actual rewriting is dealyed until the egress
// pipeline so that the original values aren't overridden and get be matched on.
// pipeline so that the original values aren't overridden and can be matched on.
struct packet_rewrites_t {
ethernet_addr_t src_mac;
ethernet_addr_t dst_mac;
Expand All @@ -189,21 +194,23 @@ struct local_metadata_t {
// used at the end of the egress pipeline to determine whether or not the
// packet should be VLAN tagged (if not dropped).
vlan_id_t vlan_id;
// True iff `vlan_id` is valid.
bool vlan_id_valid;

bool vlan_id_valid; // True iff `vlan_id` is valid.
bool admit_to_l3;
vrf_id_t vrf_id;
packet_rewrites_t packet_rewrites;
bit<16> l4_src_port;
bit<16> l4_dst_port;
bit<WCMP_SELECTOR_INPUT_BITWIDTH> wcmp_selector_input;
// GRE tunnel encap related fields.

// Tunnel related fields.
bool apply_tunnel_decap_at_end_of_pre_ingress;
bool apply_tunnel_encap_at_egress;
ipv6_addr_t tunnel_encap_src_ipv6;
ipv6_addr_t tunnel_encap_dst_ipv6;
// mirroring data, we can't group them into a struct, because BMv2 doesn't
// support passing structs in clone3.

// Mirroring related fields.
// We can't group them into a struct as BMv2 doesn't support passing structs
// into clone3.
bool mirror_session_id_valid;
mirror_session_id_t mirror_session_id_value;
@field_list(PreservedFieldList.CLONE_I2E_MIRRORING)
Expand Down
11 changes: 10 additions & 1 deletion sai_p4/fixed/minimum_guaranteed_sizes.p4
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
// Instantiations of SAI P4 can override these sizes by defining the following
// macros.

#ifndef IPV6_TUNNEL_TERMINATION_TABLE_MINIMUM_GUARANTEED_SIZE
#define IPV6_TUNNEL_TERMINATION_TABLE_MINIMUM_GUARANTEED_SIZE 0
#endif

#ifndef NEXTHOP_TABLE_MINIMUM_GUARANTEED_SIZE
#define NEXTHOP_TABLE_MINIMUM_GUARANTEED_SIZE 0
#endif
Expand Down Expand Up @@ -69,7 +73,12 @@
#define WCMP_GROUP_SELECTOR_MAX_GROUP_SIZE 0
#endif

// The max weight of an individual member when using the SUM_OF_MEMBERS size
// The maximum sum of weights or members for each wcmp group.
#ifndef WCMP_GROUP_SELECTOR_MAX_GROUP_SIZE_TOR
#define WCMP_GROUP_SELECTOR_MAX_GROUP_SIZE_TOR 0
#endif

// The max weight of an individual member when using the SUM_OF_MEMBERS size
// semantics. This value is ignored in the SUM_OF_WEIGHTS semantics.
#ifndef WCMP_GROUP_SELECTOR_MAX_MEMBER_WEIGHT
#define WCMP_GROUP_SELECTOR_MAX_MEMBER_WEIGHT 0
Expand Down
30 changes: 30 additions & 0 deletions sai_p4/fixed/parser.p4
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ parser packet_parser(packet_in packet, out headers_t headers,
local_metadata.l4_src_port = 0;
local_metadata.l4_dst_port = 0;
local_metadata.wcmp_selector_input = 0;
local_metadata.apply_tunnel_decap_at_end_of_pre_ingress = false;
local_metadata.apply_tunnel_encap_at_egress = false;
local_metadata.tunnel_encap_src_ipv6 = 0;
local_metadata.tunnel_encap_dst_ipv6 = 0;
local_metadata.mirror_session_id_valid = false;
local_metadata.color = MeterColor_t.GREEN;
local_metadata.ingress_port = (port_id_t)standard_metadata.ingress_port;
Expand All @@ -40,6 +44,18 @@ parser packet_parser(packet_in packet, out headers_t headers,
state parse_ipv4 {
packet.extract(headers.ipv4);
transition select(headers.ipv4.protocol) {
IP_PROTOCOL_IPV4: parse_ipv4_in_ip;
IP_PROTOCOL_IPV6: parse_ipv6_in_ip;
IP_PROTOCOL_ICMP: parse_icmp;
IP_PROTOCOL_TCP: parse_tcp;
IP_PROTOCOL_UDP: parse_udp;
_: accept;
}
}

state parse_ipv4_in_ip {
packet.extract(headers.inner_ipv4);
transition select(headers.inner_ipv4.protocol) {
IP_PROTOCOL_ICMP: parse_icmp;
IP_PROTOCOL_TCP: parse_tcp;
IP_PROTOCOL_UDP: parse_udp;
Expand All @@ -50,6 +66,18 @@ parser packet_parser(packet_in packet, out headers_t headers,
state parse_ipv6 {
packet.extract(headers.ipv6);
transition select(headers.ipv6.next_header) {
IP_PROTOCOL_IPV4: parse_ipv4_in_ip;
IP_PROTOCOL_IPV6: parse_ipv6_in_ip;
IP_PROTOCOL_ICMPV6: parse_icmp;
IP_PROTOCOL_TCP: parse_tcp;
IP_PROTOCOL_UDP: parse_udp;
_: accept;
}
}

state parse_ipv6_in_ip {
packet.extract(headers.inner_ipv6);
transition select(headers.inner_ipv6.next_header) {
IP_PROTOCOL_ICMPV6: parse_icmp;
IP_PROTOCOL_TCP: parse_tcp;
IP_PROTOCOL_UDP: parse_udp;
Expand Down Expand Up @@ -102,6 +130,8 @@ control packet_deparser(packet_out packet, in headers_t headers) {
packet.emit(headers.tunnel_encap_gre);
packet.emit(headers.ipv4);
packet.emit(headers.ipv6);
packet.emit(headers.inner_ipv4);
packet.emit(headers.inner_ipv6);
packet.emit(headers.arp);
packet.emit(headers.icmp);
packet.emit(headers.tcp);
Expand Down
102 changes: 102 additions & 0 deletions sai_p4/fixed/tunnel_termination.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Tunnel termination aka decap, modeled after `saitunnel.h`,

// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SAI_TUNNEL_TERMINATION_P4_
#define SAI_TUNNEL_TERMINATION_P4_

// Should be applied at the beginning of the pre-ingress stage.
control tunnel_termination_lookup(in headers_t headers,
inout local_metadata_t local_metadata) {

// Sets SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_VR_ID.
@id(MARK_FOR_TUNNEL_DECAP_AND_SET_VRF_ACTION_ID)
action mark_for_tunnel_decap_and_set_vrf(vrf_id_t vrf_id) {
// Actual decap is delayed until the end of the pre-ingress stage.
local_metadata.apply_tunnel_decap_at_end_of_pre_ingress = true;
local_metadata.vrf_id = vrf_id;
}

// Models SAI_TUNNEL_TERM_TABLE.
// Currently, we only model IPv6 decap of IP-in-IP packets
// TODO: Remove `@unsupported` annotation once the table is
// supported by the switch stack.
@unsupported
@p4runtime_role(P4RUNTIME_ROLE_ROUTING)
@id(IPV6_TUNNEL_TERMINATION_TABLE_ID)
table ipv6_tunnel_termination_table {
key = {
// Sets `SAI_TUNNEL_TERM_TABLE_ENTRY_ATTR_DST_IP[_MASK]`.
headers.ipv6.dst_addr : ternary
@id(1) @name("dst_ipv6") @format(IPV6_ADDRESS);
}
actions = {
@proto_id(1) mark_for_tunnel_decap_and_set_vrf;
}
size = IPV6_TUNNEL_TERMINATION_TABLE_MINIMUM_GUARANTEED_SIZE;
}

apply {
// Currently, we only model decap of IP-in-IPv6 packets
// (SAI_TUNNEL_TYPE_IPINIP).
if (headers.ipv6.isValid()) {
// IP-in-IP encapsulation: 4in6 or 6in6.
if (headers.ipv6.next_header == IP_PROTOCOL_IPV4 ||
headers.ipv6.next_header == IP_PROTOCOL_IPV6) {
ipv6_tunnel_termination_table.apply();
}
}
}

}

// Should be applied at the end of the pre-ingress stage.
control tunnel_termination_decap(inout headers_t headers,
in local_metadata_t local_metadata) {
apply {
if (local_metadata.apply_tunnel_decap_at_end_of_pre_ingress) {
// Currently, this should only ever be set for IP-in-IPv6 packets.
// TODO: Remove guard once p4-symbolic suports assertions.
#ifndef PLATFORM_P4SYMBOLIC
assert(headers.ipv6.isValid());
assert((headers.inner_ipv4.isValid() && !headers.inner_ipv6.isValid()) ||
(!headers.inner_ipv4.isValid() && headers.inner_ipv6.isValid()));
#endif

// Decap: strip outer header and replace with inner header.
headers.ipv6.setInvalid();
if (headers.inner_ipv4.isValid()) {
headers.ethernet.ether_type = ETHERTYPE_IPV4;
// TODO: Support header assignment in
// p4-symbolic and remove this guard.
#ifndef PLATFORM_P4SYMBOLIC
headers.ipv4 = headers.inner_ipv4;
#endif
headers.inner_ipv4.setInvalid();
}
if (headers.inner_ipv6.isValid()) {
headers.ethernet.ether_type = ETHERTYPE_IPV6;
// TODO: Support header assignment in
// p4-symbolic and remove this guard.
#ifndef PLATFORM_P4SYMBOLIC
headers.ipv6 = headers.inner_ipv6;
#endif
headers.inner_ipv6.setInvalid();
}
}
}
}

#endif // SAI_TUNNEL_TERMINATION_P4_
2 changes: 0 additions & 2 deletions sai_p4/instantiations/google/acl_pre_ingress.p4
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,6 @@ control acl_pre_ingress(in headers_t headers,
ip_protocol = headers.ipv6.next_header;
}

local_metadata.vrf_id = kDefaultVrf;

#if defined(SAI_INSTANTIATION_MIDDLEBLOCK)
acl_pre_ingress_table.apply();
#elif defined(SAI_INSTANTIATION_FABRIC_BORDER_ROUTER)
Expand Down
3 changes: 3 additions & 0 deletions sai_p4/instantiations/google/fabric_border_router.p4
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "../../fixed/vlan.p4"
#include "../../fixed/drop_martians.p4"
#include "../../fixed/packet_rewrites.p4"
#include "../../fixed/tunnel_termination.p4"
#include "acl_egress.p4"
#include "acl_ingress.p4"
#include "acl_pre_ingress.p4"
Expand All @@ -32,8 +33,10 @@ control ingress(inout headers_t headers,
apply {
packet_out_decap.apply(headers, local_metadata, standard_metadata);
if (!local_metadata.bypass_ingress) {
tunnel_termination_lookup.apply(headers, local_metadata);
vlan_untag.apply(headers, local_metadata, standard_metadata);
acl_pre_ingress.apply(headers, local_metadata, standard_metadata);
tunnel_termination_decap.apply(headers, local_metadata);
admit_google_system_mac.apply(headers, local_metadata);
l3_admit.apply(headers, local_metadata, standard_metadata);
routing.apply(headers, local_metadata, standard_metadata);
Expand Down
40 changes: 40 additions & 0 deletions sai_p4/instantiations/google/fabric_border_router.p4info.pb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,32 @@ pkg_info {
arch: "v1model"
organization: "Google"
}
tables {
preamble {
id: 33554507
name: "ingress.tunnel_termination_lookup.ipv6_tunnel_termination_table"
alias: "ipv6_tunnel_termination_table"
annotations: "@unsupported"
annotations: "@p4runtime_role(\"sdn_controller\")"
}
match_fields {
id: 1
name: "dst_ipv6"
annotations: "@format(IPV6_ADDRESS)"
bitwidth: 128
match_type: TERNARY
}
action_refs {
id: 16777238
annotations: "@proto_id(1)"
}
action_refs {
id: 21257015
annotations: "@defaultonly"
scope: DEFAULT_ONLY
}
size: 128
}
tables {
preamble {
id: 33554689
Expand Down Expand Up @@ -769,6 +795,20 @@ actions {
annotations: "@sai_action(SAI_PACKET_ACTION_DROP)"
}
}
actions {
preamble {
id: 16777238
name: "ingress.tunnel_termination_lookup.mark_for_tunnel_decap_and_set_vrf"
alias: "mark_for_tunnel_decap_and_set_vrf"
}
params {
id: 1
name: "vrf_id"
type_name {
name: "vrf_id_t"
}
}
}
actions {
preamble {
id: 16777472
Expand Down
3 changes: 3 additions & 0 deletions sai_p4/instantiations/google/middleblock.p4
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "../../fixed/vlan.p4"
#include "../../fixed/drop_martians.p4"
#include "../../fixed/packet_rewrites.p4"
#include "../../fixed/tunnel_termination.p4"
#include "acl_ingress.p4"
#include "acl_pre_ingress.p4"
#include "admit_google_system_mac.p4"
Expand All @@ -32,8 +33,10 @@ control ingress(inout headers_t headers,
apply {
packet_out_decap.apply(headers, local_metadata, standard_metadata);
if (!local_metadata.bypass_ingress) {
tunnel_termination_lookup.apply(headers, local_metadata);
vlan_untag.apply(headers, local_metadata, standard_metadata);
acl_pre_ingress.apply(headers, local_metadata, standard_metadata);
tunnel_termination_decap.apply(headers, local_metadata);
admit_google_system_mac.apply(headers, local_metadata);
l3_admit.apply(headers, local_metadata, standard_metadata);
routing.apply(headers, local_metadata, standard_metadata);
Expand Down
Loading

0 comments on commit abd606e

Please sign in to comment.