Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions .github/buildomat/common.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
#!/bin/bash

# The tofino2 has 20 stages, and the current sidecar.p4 needs all 20 of them.
# Specifying the number of stages isn't strictly necessary, but it allows us to
# track when we exceed the current ceiling. The underlying intention is to grow
# deliberately and thoughtfully, given the limited space on the ASIC.
#
# Note: this now seems silly since we have maxed out the number of stages, but
# we want to leave this check and note in place should we ever find a way to
# reduce our footprint below 20 stages.
TOFINO_STAGES=20
# The tofino2 has 20 stages. The base sidecar.p4 needs 15 stages, and with
# multicast enabled it needs 18. Specifying the number of stages isn't
# strictly necessary, but it allows us to track when we exceed the current
# ceiling. The underlying intention is to grow deliberately and thoughtfully,
# given the limited space on the ASIC.
TOFINO_STAGES=15

# These describe which version of the SDE to download and where to find it
SDE_COMMIT=2a6b33211c9675996dcb99fe939045506667ae94
Expand Down
8 changes: 7 additions & 1 deletion .github/buildomat/packet-test-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ if [ x$MULTICAST == x ]; then
CODEGEN_FEATURES=--multicast
SWADM_FEATURES=--features=multicast
fi


if [ x$MULTICAST == x ]; then
TOFINO_STAGES=15
else
TOFINO_STAGES=18
fi

function cleanup {
set +o errexit
set +o pipefail
Expand Down
70 changes: 66 additions & 4 deletions asic/src/softnpu/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ impl TableOps<Handle> for Table {
trace!(hdl.log, "match_data:\n{:#?}", match_data);
trace!(hdl.log, "action_data:\n{:#?}", action_data);

// Route tables are idx-only in sidecar-lite and route_ttl_is_1
// is ignored here.
//
// TODO: remove compat once https://github.com/oxidecomputer/sidecar-lite/pull/152
// is merged and sidecar-lite updates route keys/actions accordingly.
let is_route_table = matches!(
self.type_,
TableType::RouteFwdIpv4 | TableType::RouteFwdIpv6
);
if is_route_table {
if route_ttl_is_1(&match_data.fields) {
trace!(hdl.log, "skipping ttl==1 route entry for {name}");
return Ok(());
}
if action_data.action == "ttl_exceeded" {
trace!(hdl.log, "skipping ttl_exceeded action for {name}");
return Ok(());
}
}

let keyset_data = keyset_data(match_data.fields, self.type_);

let (action, parameter_data) = match (
Expand Down Expand Up @@ -428,6 +448,22 @@ impl TableOps<Handle> for Table {
}
("rewrite", params)
}
#[cfg(feature = "multicast")]
(TableType::PortMacAddressMcast, "rewrite") => {
let mut params = Vec::new();
for arg in action_data.args {
match arg.value {
ValueTypes::U64(v) => {
let mac = v.to_le_bytes();
params.extend_from_slice(&mac[0..6]);
}
ValueTypes::Ptr(v) => {
params.extend_from_slice(v.as_slice());
}
}
}
("rewrite", params)
}
(TableType::NatIngressIpv4, "forward_ipv4_to")
| (TableType::NatIngressIpv6, "forward_ipv6_to")
| (TableType::AttachedSubnetIpv4, "forward_to_v4")
Expand Down Expand Up @@ -573,6 +609,15 @@ impl TableOps<Handle> for Table {
trace!(hdl.log, "table: {name}");
trace!(hdl.log, "match_data:\n{:#?}", match_data);

let is_route_table = matches!(
self.type_,
TableType::RouteFwdIpv4 | TableType::RouteFwdIpv6
);
if is_route_table && route_ttl_is_1(&match_data.fields) {
trace!(hdl.log, "skipping ttl==1 route entry delete for {name}");
return Ok(());
}

let keyset_data = keyset_data(match_data.fields, self.type_);

trace!(hdl.log, "sending request to softnpu");
Expand Down Expand Up @@ -632,10 +677,12 @@ fn keyset_data(match_data: Vec<MatchEntryField>, table: TableType) -> Vec<u8> {
serialize_value_type(&x, &mut data);
keyset_data.extend_from_slice(&data[..2]);
}
TableType::RouteIdxIpv4 => {
// "idx" => exact => bit<16>
serialize_value_type(&x, &mut data);
keyset_data.extend_from_slice(&data[..2]);
TableType::RouteFwdIpv4 | TableType::RouteFwdIpv6 => {
// sidecar-lite route keys are idx-only.
if m.name == "idx" {
serialize_value_type(&x, &mut data);
keyset_data.extend_from_slice(&data[..2]);
}
}
TableType::NatIngressIpv4 => {
// "dst_addr" => hdr.ipv4.dst: exact => bit<32>
Expand Down Expand Up @@ -725,3 +772,18 @@ fn serialize_value_type_be(x: &ValueTypes, data: &mut Vec<u8>) {
}
}
}

fn route_ttl_is_1(fields: &[MatchEntryField]) -> bool {
fields.iter().any(|field| {
if field.name != "route_ttl_is_1" {
return false;
}
match &field.value {
MatchEntryValue::Value(ValueTypes::U64(v)) => *v != 0,
MatchEntryValue::Value(ValueTypes::Ptr(v)) => {
v.first().is_some_and(|b| *b != 0)
}
_ => false,
}
})
}
31 changes: 16 additions & 15 deletions asic/src/tofino_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ pub mod ports;
fn table_name(type_: TableType) -> &'static str {
match type_ {
TableType::RouteIdxIpv4 => {
"pipe.Ingress.l3_router.Router4.lookup_idx.lookup"
"pipe.Ingress.l3_router.router4.lookup_idx.lookup"
}
TableType::RouteFwdIpv4 => {
"pipe.Ingress.l3_router.Router4.lookup_idx.route"
"pipe.Ingress.l3_router.router4.lookup_idx.route"
}
TableType::RouteIdxIpv6 => {
"pipe.Ingress.l3_router.Router6.lookup_idx.lookup"
"pipe.Ingress.l3_router.router6.lookup_idx.lookup"
}
TableType::RouteFwdIpv6 => {
"pipe.Ingress.l3_router.Router6.lookup_idx.route"
"pipe.Ingress.l3_router.router6.lookup_idx.route"
}
#[cfg(feature = "multicast")]
TableType::RouteIpv4Mcast => {
Expand All @@ -44,13 +44,15 @@ fn table_name(type_: TableType) -> &'static str {
}
TableType::ArpIpv4 => "pipe.Ingress.l3_router.Arp.tbl",
TableType::NeighborIpv6 => "pipe.Ingress.l3_router.Ndp.tbl",
TableType::PortMacAddress => "pipe.Ingress.mac_rewrite.mac_rewrite",
TableType::PortMacAddress => {
"pipe.Egress.unicast_mac_rewrite.mac_rewrite"
}
TableType::PortAddrIpv4 => "pipe.Ingress.filter.switch_ipv4_addr",
TableType::PortAddrIpv6 => "pipe.Ingress.filter.switch_ipv6_addr",
TableType::NatIngressIpv4 => "pipe.Ingress.nat_ingress.ingress_ipv4",
TableType::NatIngressIpv6 => "pipe.Ingress.nat_ingress.ingress_ipv6",
TableType::UplinkIngress => "pipe.Ingress.filter.uplink_ports",
TableType::UplinkEgress => "pipe.Ingress.egress_filter.egress_filter",
TableType::UplinkEgress => "pipe.Egress.egress_filter.egress_filter",
TableType::AttachedSubnetIpv4 => {
"pipe.Ingress.attached_subnet_ingress.attached_subnets_v4"
}
Expand Down Expand Up @@ -78,7 +80,9 @@ fn table_name(type_: TableType) -> &'static str {
"pipe.Ingress.nat_ingress.ingress_ipv6_mcast"
}
#[cfg(feature = "multicast")]
TableType::PortMacAddressMcast => "pipe.Egress.mac_rewrite.mac_rewrite",
TableType::PortMacAddressMcast => {
"pipe.Egress.mcast_mac_rewrite.mac_rewrite"
}
#[cfg(feature = "multicast")]
TableType::McastEgressDecapPorts => {
"pipe.Egress.mcast_egress.tbl_decap_ports"
Expand All @@ -96,9 +100,13 @@ fn counter_table_name(id: CounterId) -> &'static str {
CounterId::Service => "pipe.Ingress.services.service_ctr",
CounterId::Ingress => "pipe.Ingress.ingress_ctr",
CounterId::Packet => "pipe.Ingress.packet_ctr",
CounterId::Egress => "pipe.Ingress.egress_ctr",
CounterId::DropPort => "pipe.Ingress.drop_port_ctr",
CounterId::DropReason => "pipe.Ingress.drop_reason_ctr",
CounterId::Forwarded => "pipe.Egress.forwarded_ctr",
CounterId::Unicast => "pipe.Egress.unicast_ctr",
CounterId::MulticastLL => "pipe.Egress.link_local_mcast_ctr",
CounterId::EgressDropPort => "pipe.Egress.drop_port_ctr",
CounterId::EgressDropReason => "pipe.Egress.drop_reason_ctr",
#[cfg(feature = "multicast")]
CounterId::Multicast(id) => mulitcast_counter_table_name(id),
}
Expand All @@ -107,16 +115,9 @@ fn counter_table_name(id: CounterId) -> &'static str {
#[cfg(feature = "multicast")]
fn mulitcast_counter_table_name(id: MulticastCounterId) -> &'static str {
match id {
MulticastCounterId::EgressDropPort => "pipe.Egress.drop_port_ctr",
MulticastCounterId::EgressDropReason => "pipe.Egress.drop_reason_ctr",
MulticastCounterId::Unicast => "pipe.Egress.unicast_ctr",
MulticastCounterId::Multicast => "pipe.Egress.mcast_ctr",
MulticastCounterId::MulticastExt => "pipe.Egress.external_mcast_ctr",
MulticastCounterId::MulticastLL => "pipe.Egress.link_local_mcast_ctr",
MulticastCounterId::MulticastUL => "pipe.Egress.underlay_mcast_ctr",
MulticastCounterId::MulticastDrop => {
"pipe.Ingress.filter.drop_mcast_ctr"
}
}
}

Expand Down
46 changes: 18 additions & 28 deletions common/src/counters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,16 @@ pub struct FecRSCounters {
pub enum CounterId {
Service,
Ingress,
Egress,
Packet,
DropPort,
DropReason,
Forwarded,
Unicast,
/// Link-local IPv6 multicast (ff02::/16). Not feature-gated because
/// link-local forwarding uses standard routing, not replication groups.
MulticastLL,
EgressDropPort,
EgressDropReason,
#[cfg(feature = "multicast")]
Multicast(MulticastCounterId),
}
Expand All @@ -227,14 +233,9 @@ pub enum CounterId {
)]
#[cfg(feature = "multicast")]
pub enum MulticastCounterId {
EgressDropPort,
EgressDropReason,
Unicast,
Multicast,
MulticastExt,
MulticastLL,
MulticastUL,
MulticastDrop,
}

impl fmt::Display for CounterId {
Expand All @@ -245,10 +246,14 @@ impl fmt::Display for CounterId {
match self {
CounterId::Service => "Service".to_string(),
CounterId::Ingress => "Ingress".to_string(),
CounterId::Egress => "Egress".to_string(),
CounterId::Packet => "Packet".to_string(),
CounterId::DropPort => "Ingress_Drop_Port".to_string(),
CounterId::DropReason => "Ingress_Drop_Reason".to_string(),
CounterId::Forwarded => "Forwarded".to_string(),
CounterId::Unicast => "Unicast".to_string(),
CounterId::MulticastLL => "Multicast_Link_Local".to_string(),
CounterId::EgressDropPort => "Egress_Drop_Port".to_string(),
CounterId::EgressDropReason => "Egress_Drop_Reason".to_string(),
#[cfg(feature = "multicast")]
CounterId::Multicast(id) => id.to_string(),
}
Expand All @@ -263,58 +268,43 @@ impl std::str::FromStr for CounterId {
match s.to_lowercase().replace(['_'], "").as_str() {
"service" => Ok(CounterId::Service),
"ingress" => Ok(CounterId::Ingress),
"egress" => Ok(CounterId::Egress),
"packet" => Ok(CounterId::Packet),
"ingressdropport" => Ok(CounterId::DropPort),
"ingressdropreason" => Ok(CounterId::DropReason),
"forwarded" => Ok(CounterId::Forwarded),
"unicast" => Ok(CounterId::Unicast),
"multicastll" | "multicastlinklocal" => Ok(CounterId::MulticastLL),
"egressdropport" => Ok(CounterId::EgressDropPort),
"egressdropreason" => Ok(CounterId::EgressDropReason),
#[cfg(feature = "multicast")]
x => match x {
"egressdropport" => {
Ok(CounterId::Multicast(MulticastCounterId::EgressDropPort))
}
"egressdropreason" => Ok(CounterId::Multicast(
MulticastCounterId::EgressDropReason,
)),
"unicast" => {
Ok(CounterId::Multicast(MulticastCounterId::Unicast))
}
"multicast" => {
Ok(CounterId::Multicast(MulticastCounterId::Multicast))
}
"multicastext" | "multicastexternal" => {
Ok(CounterId::Multicast(MulticastCounterId::MulticastExt))
}
"multicastll" | "multicastlinklocal" => {
Ok(CounterId::Multicast(MulticastCounterId::MulticastLL))
}
"multicastul" | "multicastunderlay" => {
Ok(CounterId::Multicast(MulticastCounterId::MulticastUL))
}
"multicastdrop" => {
Ok(CounterId::Multicast(MulticastCounterId::MulticastDrop))
}
x => Err(format!("No such counter: {x}")),
},
#[cfg(not(feature = "multicast"))]
x => Err(format!("No such counter: {x}")),
}
}
}

#[cfg(feature = "multicast")]
impl fmt::Display for MulticastCounterId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
MulticastCounterId::EgressDropPort => "Egress_Drop_Port",
MulticastCounterId::EgressDropReason => "Egress_Drop_Reason",
MulticastCounterId::Unicast => "Unicast",
MulticastCounterId::Multicast => "Multicast",
MulticastCounterId::MulticastExt => "Multicast_External",
MulticastCounterId::MulticastLL => "Multicast_Link_Local",
MulticastCounterId::MulticastUL => "Multicast_Underlay",
MulticastCounterId::MulticastDrop => "Multicast_Drop",
}
)
}
Expand Down
2 changes: 1 addition & 1 deletion common/src/illumos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/
//
// Copyright 2025 Oxide Computer Company
// Copyright 2026 Oxide Computer Company

//! Illumos-specific common modules and operations.

Expand Down
19 changes: 0 additions & 19 deletions dpd-client/tests/integration_tests/mcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1710,14 +1710,6 @@ async fn test_ipv6_multicast_invalid_destination_mac() -> TestResult {
let ctr_baseline =
switch.get_counter("multicast_invalid_mac", None).await.unwrap();

let port_label_ingress = switch.port_label(ingress).unwrap();

// Check the Multicast_Drop counter baseline for the ingress port
let drop_mcast_baseline = switch
.get_counter(&port_label_ingress, Some("multicast_drop"))
.await
.unwrap();

switch.packet_test(vec![test_pkt], expected_pkts).unwrap();

check_counter_incremented(
Expand All @@ -1730,17 +1722,6 @@ async fn test_ipv6_multicast_invalid_destination_mac() -> TestResult {
.await
.unwrap();

// Verify that the Multicast_Drop counter also incremented
check_counter_incremented(
switch,
&port_label_ingress,
drop_mcast_baseline,
1,
Some("multicast_drop"),
)
.await
.unwrap();

cleanup_test_group(switch, get_group_ip(&created_group), TEST_TAG).await
}

Expand Down
12 changes: 1 addition & 11 deletions dpd-client/tests/integration_tests/table_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,7 @@ use crate::integration_tests::common::prelude::*;
// investigating. If it only changes by an entry or two, it's fine to just
// adjust the constant below to match the observed result.
//
// TODO: Multicast drops IPv4 LPM capacity to 7164 (from 8187) due to
// ingress TCAM pressure. Investigate moving MulticastRouter4/6 into the
// egress pipeline to reclaim capacity.
#[cfg(feature = "multicast")]
const IPV4_LPM_SIZE: usize = 7164; // ipv4 forwarding table
#[cfg(not(feature = "multicast"))]
const IPV4_LPM_SIZE: usize = 8187; // ipv4 forwarding table

#[cfg(feature = "multicast")]
const IPV6_LPM_SIZE: usize = 1023; // ipv6 forwarding table
#[cfg(not(feature = "multicast"))]
const IPV4_LPM_SIZE: usize = 8191; // ipv4 forwarding table
const IPV6_LPM_SIZE: usize = 1023; // ipv6 forwarding table

const SWITCH_IPV4_ADDRS_SIZE: usize = 511; // ipv4 addrs assigned to our ports
Expand Down
Loading