Skip to content

Commit

Permalink
[SAIP4] Switch support for queue names. split out ToR behaviors. Move…
Browse files Browse the repository at this point in the history
… TTL decrement into packet_rewrites.p4 and delete ttl.p4. All packet rewrites modeling now occurs in one place. Add priorities for acl_ingress_table and acl_ingress_qos_table. [SAI-P4] Add version where deprecated `set_nexthop` action is removed. [SAI-P4] Add version where deprecated `set_nexthop` action is removed. [SAI-P4] drop packets with localhost source/destination IPv4/IPv6 address. (sonic-net#280)

* acl_pre_ingress_vlan table should match on ip_type.
[SAI P4] Small semantics-preservings tweaks in Packet IO test.
[ofpd] Add support for drop flows in ACL ingress QOS table.
[ofpd][p4] Add support for forwarding actions in acl qos table.
Set ether_type field for AclQosTableGenerator.
Fetching P4Info for ToR got crossed.

* [SAIP4] Add class to conveniently construct table entries for testing.
remove out_port from Ingress ACL tables.

* [SAIP4] Switch support for queue names. split out ToR behaviors.
Move TTL decrement into packet_rewrites.p4 and delete ttl.p4.
All packet rewrites modeling now occurs in one place.
Add priorities for acl_ingress_table and acl_ingress_qos_table.
[SAI-P4] Add version where deprecated `set_nexthop` action is removed.
[SAI-P4] Add version where deprecated `set_nexthop` action is removed.
[SAI-P4] drop packets with localhost source/destination IPv4/IPv6 address.

---------

Co-authored-by: rhalstea <rhalstea@google.com>
Co-authored-by: smolkaj <smolkaj@google.com>
Co-authored-by: kishanps <kishanps@google.com>
Co-authored-by: bhagatgit <115375369+bhagatgit@users.noreply.github.com>
  • Loading branch information
5 people authored Jul 4, 2024
1 parent 8c37944 commit dcd6fc3
Show file tree
Hide file tree
Showing 22 changed files with 293 additions and 4,526 deletions.
4 changes: 2 additions & 2 deletions p4rt_app/tests/golden_outputs/p4_constraints_test.expected
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ updates {
UNKNOWN: Batch failed, individual results:
#1: INVALID_ARGUMENT: All entries must satisfy:

In @entry_restriction of table 'egress.acl_egress.acl_egress_table'; at offset line 6, columns 5 to 73:
In @entry_restriction of table 'egress.acl_egress.acl_egress_table'; at offset line 8, columns 5 to 73:
| // Only allow IP field matches for IP packets.
6 | ip_protocol::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
8 | ip_protocol::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

But your entry does not.
Expand Down
3 changes: 1 addition & 2 deletions sai_p4/fixed/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ filegroup(
"parser.p4",
"roles.h",
"routing.p4",
"ttl.p4",
"vlan.p4",
"vlan.p4",
],
)

Expand Down
35 changes: 30 additions & 5 deletions sai_p4/fixed/drop_martians.p4
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@ const ipv6_addr_t IPV6_MULTICAST_MASK =
const ipv6_addr_t IPV6_MULTICAST_VALUE =
0xff00_0000_0000_0000_0000_0000_0000_0000;

// ::1/128
const ipv6_addr_t IPV6_LOOPBACK_MASK =
0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
const ipv6_addr_t IPV6_LOOPBACK_VALUE =
0x0000_0000_0000_0000_0000_0000_0000_0001;

const ipv4_addr_t IPV4_MULTICAST_MASK = 0xf0_00_00_00;
const ipv4_addr_t IPV4_MULTICAST_VALUE = 0xe0_00_00_00;

const ipv4_addr_t IPV4_BROADCAST_VALUE = 0xff_ff_ff_ff;

// 127.0.0.0/8
const ipv4_addr_t IPV4_LOOPBACK_MASK = 0xff_00_00_00;
const ipv4_addr_t IPV4_LOOPBACK_VALUE = 0x7f_00_00_00;

// I/G bit = 1 means multicast.
const ethernet_addr_t MAC_MULTICAST_MASK = 0x01_00_00_00_00_00;
const ethernet_addr_t MAC_MULTICAST_VALUE = 0x01_00_00_00_00_00;
Expand All @@ -21,33 +31,48 @@ const ethernet_addr_t MAC_MULTICAST_VALUE = 0x01_00_00_00_00_00;
#define IS_IPV6_MULTICAST(address) \
(address & IPV6_MULTICAST_MASK == IPV6_MULTICAST_VALUE)

#define IS_IPV6_LOOPBACK(address) \
(address & IPV6_LOOPBACK_MASK == IPV6_LOOPBACK_VALUE)

#define IS_IPV4_MULTICAST_OR_BROADCAST(address) \
((address & IPV4_MULTICAST_MASK == IPV4_MULTICAST_VALUE) || \
(address == IPV4_BROADCAST_VALUE))

#define IS_IPV4_LOOPBACK(address) \
(address & IPV4_LOOPBACK_MASK == IPV4_LOOPBACK_VALUE)

#define IS_MAC_MULTICAST(address) \
(address & MAC_MULTICAST_MASK == MAC_MULTICAST_VALUE)


control drop_martians(in headers_t headers,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
apply {
// Drop the packet if:
// - Src or dst IPv6 addresses are in multicast range; or
// - Src or dst IPv4 addresses are in multicast or broadcast range.
// - I/G bit in dst MAC address is set (i.e. a multicast address)
// - Src/Dst IPv6 addresses are in multicast range; or
// - Src/Dst IPv4 addresses are in multicast or broadcast range; or
// - I/G bit in dst MAC address is set (i.e. a multicast address); or
// - Src/Dst IPv4/IPv6 address is a loopback address.
// Rationale:
// Src IP multicast drop: https://www.rfc-editor.org/rfc/rfc1812#section-5.3.7
// Dst IP multicast drop: multicast is not yet modeled and our switches drop
// multicast packets for now.
// Src/Dst IP loopback drop: https://en.wikipedia.org/wiki/Localhost#Packet_processing
// "Packets received on a non-loopback interface with a loopback source
// or destination address must be dropped."
// Dst MAC multicast drop: multicast is not yet modeled and our switches
// drop multicast packets for now.
if ((headers.ipv6.isValid() &&
(IS_IPV6_MULTICAST(headers.ipv6.src_addr) ||
IS_IPV6_MULTICAST(headers.ipv6.dst_addr))) ||
IS_IPV6_MULTICAST(headers.ipv6.dst_addr) ||
IS_IPV6_LOOPBACK(headers.ipv6.src_addr) ||
IS_IPV6_LOOPBACK(headers.ipv6.dst_addr))) ||
(headers.ipv4.isValid() &&
(IS_IPV4_MULTICAST_OR_BROADCAST(headers.ipv4.src_addr) ||
IS_IPV4_MULTICAST_OR_BROADCAST(headers.ipv4.dst_addr))) ||
IS_IPV4_MULTICAST_OR_BROADCAST(headers.ipv4.dst_addr) ||
IS_IPV4_LOOPBACK(headers.ipv4.src_addr) ||
IS_IPV4_LOOPBACK(headers.ipv4.dst_addr))) ||
(headers.ethernet.isValid() &&
IS_MAC_MULTICAST(headers.ethernet.dst_addr))) {
mark_to_drop(standard_metadata);
Expand Down
16 changes: 16 additions & 0 deletions sai_p4/fixed/packet_rewrites.p4
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,22 @@ control packet_rewrites(inout headers_t headers,
if (local_metadata.admit_to_l3) {
headers.ethernet.src_addr = local_metadata.packet_rewrites.src_mac;
headers.ethernet.dst_addr = local_metadata.packet_rewrites.dst_mac;

if (headers.ipv4.isValid()) {
if (headers.ipv4.ttl <= 1) {
mark_to_drop(standard_metadata);
} else {
headers.ipv4.ttl = headers.ipv4.ttl - 1;
}
}

if (headers.ipv6.isValid()) {
if (headers.ipv6.hop_limit <= 1) {
mark_to_drop(standard_metadata);
} else {
headers.ipv6.hop_limit = headers.ipv6.hop_limit - 1;
}
}
}
}
} // control packet_rewrites
Expand Down
32 changes: 0 additions & 32 deletions sai_p4/fixed/ttl.p4

This file was deleted.

Binary file removed sai_p4/instantiations/google/.acl_ingress.p4.swp
Binary file not shown.
30 changes: 22 additions & 8 deletions sai_p4/instantiations/google/acl_egress.p4
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,20 @@ control acl_egress(in headers_t headers,
@id(ACL_EGRESS_TABLE_ID)
@sai_acl(EGRESS)
@entry_restriction("
#ifdef SAI_INSTANTIATION_FABRIC_BORDER_ROUTER
// Forbid using ether_type for IP packets (by convention, use is_ip* instead).
ether_type != 0x0800 && ether_type != 0x86dd;
dscp::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
#endif
// Only allow IP field matches for IP packets.
ip_protocol::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
#if defined(SAI_INSTANTIATION_TOR)
dst_ipv6::mask != 0 -> is_ipv6 == 1;
#endif
#ifdef SAI_INSTANTIATION_FABRIC_BORDER_ROUTER
// Only allow l4_dst_port matches for TCP/UDP packets.
l4_dst_port::mask != 0 -> (ip_protocol == 6 || ip_protocol == 17);
#endif
// Forbid illegal combinations of IP_TYPE fields.
is_ip::mask != 0 -> (is_ipv4::mask == 0 && is_ipv6::mask == 0);
is_ipv4::mask != 0 -> (is_ip::mask == 0 && is_ipv6::mask == 0);
Expand All @@ -51,12 +58,16 @@ control acl_egress(in headers_t headers,
")
table acl_egress_table {
key = {
#ifdef SAI_INSTANTIATION_FABRIC_BORDER_ROUTER
headers.ethernet.ether_type : ternary @name("ether_type") @id(1)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE);
#endif
ip_protocol : ternary @name("ip_protocol") @id(2)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL);
#ifdef SAI_INSTANTIATION_FABRIC_BORDER_ROUTER
local_metadata.l4_dst_port : ternary @name("l4_dst_port") @id(3)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT);
#endif
(port_id_t)standard_metadata.egress_port: optional @name("out_port")
@id(4) @sai_field(SAI_ACL_TABLE_ATTR_FIELD_OUT_PORT);
headers.ipv4.isValid() || headers.ipv6.isValid() : optional @name("is_ip")
Expand All @@ -65,13 +76,22 @@ control acl_egress(in headers_t headers,
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/IPV4ANY);
headers.ipv6.isValid() : optional @name("is_ipv6") @id(7)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/IPV6ANY);
#ifdef SAI_INSTANTIATION_FABRIC_BORDER_ROUTER
// Field for v4 and v6 DSCP bits.
dscp : ternary @name("dscp") @id(8)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_DSCP);
#endif
#if defined(SAI_INSTANTIATION_TOR)
headers.ipv6.dst_addr[127:64] : ternary @name("dst_ipv6") @id(9)
@composite_field(
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD3),
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD2)
) @format(IPV6_ADDRESS);
#endif
}
actions = {
@proto_id(1) acl_drop(standard_metadata);
#ifdef SAI_INSTANTIATION_TOR
#if defined(SAI_INSTANTIATION_TOR)
@proto_id(2) acl_egress_forward();
#endif
@defaultonly NoAction;
Expand All @@ -85,8 +105,6 @@ control acl_egress(in headers_t headers,
@sai_acl(EGRESS)
@p4runtime_role(P4RUNTIME_ROLE_SDN_CONTROLLER)
@entry_restriction("
// Forbid using ether_type for IP packets (by convention, use is_ip* instead).
ether_type != 0x0800 && ether_type != 0x86dd;
// Only allow IP field matches for IP packets.
ip_protocol::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
// Only allow l4_dst_port matches for TCP/UDP packets.
Expand All @@ -110,9 +128,6 @@ control acl_egress(in headers_t headers,
headers.ipv6.isValid() : optional
@id(3) @name("is_ipv6")
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/IPV6ANY);
headers.ethernet.ether_type : ternary
@id(4) @name("ether_type")
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE);
ip_protocol : ternary
@id(5) @name("ip_protocol")
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL);
Expand Down Expand Up @@ -147,8 +162,7 @@ control acl_egress(in headers_t headers,
acl_egress_table.apply();
#elif defined(SAI_INSTANTIATION_TOR)
acl_egress_table.apply();
// TODO: Not enough SAI resources for the second EFP bank.
// acl_egress_dhcp_to_host_table.apply();
acl_egress_dhcp_to_host_table.apply();
#endif
}
} // control ACL_EGRESS
Expand Down
51 changes: 31 additions & 20 deletions sai_p4/instantiations/google/acl_ingress.p4
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ control acl_ingress(in headers_t headers,

// Copy the packet to the CPU, and forward the original packet.
@id(ACL_INGRESS_COPY_ACTION_ID)
#if defined(SAI_INSTANTIATION_TOR)
// In ToRs, the acl_ingress_table copy action will not apply a rate limit.
// Rate limits will be applied by acl_ingress_qos_table cancel_copy actions.
@sai_action(SAI_PACKET_ACTION_COPY)
action acl_copy(@sai_action_param(QOS_QUEUE) @id(1) qos_queue_t qos_queue) {
acl_ingress_counter.count();
marked_to_copy = true;
}
#else
@sai_action(SAI_PACKET_ACTION_COPY, SAI_PACKET_COLOR_GREEN)
@sai_action(SAI_PACKET_ACTION_FORWARD, SAI_PACKET_COLOR_YELLOW)
@sai_action(SAI_PACKET_ACTION_FORWARD, SAI_PACKET_COLOR_RED)
Expand All @@ -56,34 +65,34 @@ control acl_ingress(in headers_t headers,
// TODO: Branch on color and model behavior for all colors.
marked_to_copy = true;
}
#endif

// Copy the packet to the CPU. The original packet is dropped.
@id(ACL_INGRESS_TRAP_ACTION_ID)
#if defined(SAI_INSTANTIATION_TOR)
// In ToRs, the acl_ingress_table trap action will not apply a rate limit.
// Rate limits will be applied by acl_ingress_qos_table cancel_copy actions.
@sai_action(SAI_PACKET_ACTION_TRAP)
#else
@sai_action(SAI_PACKET_ACTION_TRAP, SAI_PACKET_COLOR_GREEN)
@sai_action(SAI_PACKET_ACTION_DROP, SAI_PACKET_COLOR_YELLOW)
@sai_action(SAI_PACKET_ACTION_DROP, SAI_PACKET_COLOR_RED)
#endif
action acl_trap(@sai_action_param(QOS_QUEUE) @id(1) qos_queue_t qos_queue) {
acl_copy(qos_queue);
mark_to_drop(standard_metadata);
}

// An experimental, metered version of `acl_trap`.
// TODO: Remove this action and meter the existing `acl_trap`
// action.
@id(ACL_INGRESS_EXPERIMENTAL_TRAP_ACTION_ID)
@sai_action(SAI_PACKET_ACTION_TRAP, SAI_PACKET_COLOR_GREEN)
@sai_action(SAI_PACKET_ACTION_DROP, SAI_PACKET_COLOR_YELLOW)
@sai_action(SAI_PACKET_ACTION_DROP, SAI_PACKET_COLOR_RED)
action acl_experimental_trap(@sai_action_param(QOS_QUEUE) @id(1) qos_queue_t qos_queue) {
acl_ingress_meter.read(local_metadata.color);
// TODO: model metering by branching on color.
acl_trap(qos_queue);
}

// Forward the packet normally (i.e., perform no action). This is useful as
// the default action, and to specify a meter but not otherwise perform any
// action.
@id(ACL_INGRESS_FORWARD_ACTION_ID)
#if defined(SAI_INSTANTIATION_TOR)
// ToRs rely on QoS queues to limit forwarded flows.
@sai_action(SAI_PACKET_ACTION_FORWARD)
action acl_forward() {
}
#else
@sai_action(SAI_PACKET_ACTION_FORWARD, SAI_PACKET_COLOR_GREEN)
@sai_action(SAI_PACKET_ACTION_DROP, SAI_PACKET_COLOR_YELLOW)
@sai_action(SAI_PACKET_ACTION_DROP, SAI_PACKET_COLOR_RED)
Expand All @@ -92,6 +101,7 @@ control acl_ingress(in headers_t headers,
// We model the behavior for GREEN packes only here.
// TODO: Branch on color and model behavior for all colors.
}
#endif

// Forward the packet normally (i.e., perform no action).
@id(ACL_INGRESS_COUNT_ACTION_ID)
Expand Down Expand Up @@ -156,6 +166,7 @@ control acl_ingress(in headers_t headers,
@p4runtime_role(P4RUNTIME_ROLE_SDN_CONTROLLER)
@id(ACL_INGRESS_TABLE_ID)
@sai_acl(INGRESS)
@sai_acl_priority(5)
@entry_restriction("
// Forbid using ether_type for IP packets (by convention, use is_ip* instead).
ether_type != 0x0800 && ether_type != 0x86dd;
Expand All @@ -171,7 +182,7 @@ control acl_ingress(in headers_t headers,
// Only allow l4_dst_port and l4_src_port matches for TCP/UDP packets.
l4_src_port::mask != 0 -> (ip_protocol == 6 || ip_protocol == 17);
l4_dst_port::mask != 0 -> (ip_protocol == 6 || ip_protocol == 17);
#ifdef SAI_INSTANTIATION_MIDDLEBLOCK
#if defined(SAI_INSTANTIATION_MIDDLEBLOCK) || defined(SAI_INSTANTIATION_TOR)
// Only allow arp_tpa matches for ARP packets.
arp_tpa::mask != 0 -> ether_type == 0x0806;
#endif
Expand Down Expand Up @@ -244,31 +255,34 @@ control acl_ingress(in headers_t headers,
@sai_udf(base=SAI_UDF_BASE_L3, offset=26, length=2)
) @format(IPV4_ADDRESS);
#endif
#ifdef SAI_INSTANTIATION_FABRIC_BORDER_ROUTER
#if defined(SAI_INSTANTIATION_FABRIC_BORDER_ROUTER) || defined(SAI_INSTANTIATION_TOR)
local_metadata.ingress_port : optional @name("in_port") @id(17)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_IN_PORT);
local_metadata.route_metadata : optional @name("route_metadata") @id(18)
@sai_field(SAI_ACL_TABLE_ATTR_FIELD_ROUTE_DST_USER_META);
#endif
}
actions = {
// TODO: add action to set color to yellow
@proto_id(1) acl_copy();
@proto_id(2) acl_trap();
@proto_id(3) acl_forward();
@proto_id(4) acl_mirror();
@proto_id(5) acl_drop(standard_metadata);
@proto_id(99) acl_experimental_trap();
@defaultonly NoAction;
}
const default_action = NoAction;
#if defined(SAI_INSTANTIATION_MIDDLEBLOCK) || defined(SAI_INSTANTIATION_FABRIC_BORDER_ROUTER)
meters = acl_ingress_meter;
counters = acl_ingress_counter;
#else
counters = acl_ingress_counter;
#endif
size = ACL_INGRESS_TABLE_MINIMUM_GUARANTEED_SIZE;
}

@id(ACL_INGRESS_QOS_TABLE_ID)
@sai_acl(INGRESS)
@sai_acl_priority(10)
@p4runtime_role(P4RUNTIME_ROLE_SDN_CONTROLLER)
@entry_restriction("
// Forbid using ether_type for IP packets (by convention, use is_ip* instead).
Expand Down Expand Up @@ -391,13 +405,11 @@ control acl_ingress(in headers_t headers,
// Only allow IP field matches for IP packets.
dst_ip::mask != 0 -> is_ipv4 == 1;
src_ip::mask != 0 -> is_ipv4 == 1;
#if defined(SAI_INSTANTIATION_EXPERIMENTAL_TOR)
dscp::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
ip_protocol::mask != 0 -> (is_ip == 1 || is_ipv4 == 1 || is_ipv6 == 1);
// Only allow l4_dst_port and l4_src_port matches for TCP/UDP packets.
l4_src_port::mask != 0 -> (ip_protocol == 6 || ip_protocol == 17);
l4_dst_port::mask != 0 -> (ip_protocol == 6 || ip_protocol == 17);
#endif
// Forbid illegal combinations of IP_TYPE fields.
is_ip::mask != 0 -> (is_ipv4::mask == 0 && is_ipv6::mask == 0);
is_ipv4::mask != 0 -> (is_ip::mask == 0 && is_ipv6::mask == 0);
Expand Down Expand Up @@ -486,7 +498,6 @@ control acl_ingress(in headers_t headers,
// additional parts of SAI in the future.
acl_ingress_table.apply();
acl_ingress_qos_table.apply();
acl_ingress_security_table.apply();
#endif

if (marked_to_copy && !cancel_copy) {
Expand Down
Loading

0 comments on commit dcd6fc3

Please sign in to comment.