Skip to content
Merged
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
16 changes: 13 additions & 3 deletions .github/buildomat/common.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
#!/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

# These describe which version of the SDE to download and where to find it
SDE_COMMIT=eb08b0b0e55792bbba206202603da0fd791ea555
SDE_PKG_SHA256=fbaea9ccd7ece70cdc20207e2f9b4750243468c6fe95c6a1fae9734201307db7
SDE_DEB_SHA256=14050fd9a08b8b0b2ec7c827fa06a51516369a81bcf616d16699302b58d8ea9a
SDE_COMMIT=e61fe02c3c1c384b2e212c90177fcea76a31fd4e
SDE_PKG_SHA256=8a87a9b0bed3c5440a173a7a41361bdeb5e7a848882da6b4aa48c8fb0043f3bd
SDE_DEB_SHA256=a292e2dd5311647c4852bb41f2532dd1fdf30325b6d04cccb7e85b873e521d5f

[ `uname -s` == "SunOS" ] && SERIES=illumos
[ `uname -s` == "SunOS" ] || SERIES=linux
Expand Down
6 changes: 1 addition & 5 deletions .github/buildomat/jobs/image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,7 @@ pfexec chown "$UID" /out

banner "P4 Codegen"
# Add gcc-12 so the p4 compiler can find cpp
# The tofino2 has 20 stages, but the current sidecar.p4 will fit into 19. We
# add the "--stages 19" here to detect if/when the program grows beyond that
# limit. It's not necessarily a problem if we grow, but given the limited space
# on the ASIC, we want to grow deliberatately and thoughtfully.
PATH=/opt/gcc-12/bin:$PATH cargo xtask codegen --stages 19
PATH=/opt/gcc-12/bin:$PATH cargo xtask codegen --stages $TOFINO_STAGES

# Preserve all the diagnostics spit out by the compiler
mkdir -p /out/p4c-diags
Expand Down
2 changes: 1 addition & 1 deletion .github/buildomat/jobs/packet-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export SDE=/opt/oxide/tofino_sde

banner "Build"
cargo build --features=tofino_asic --bin dpd --bin swadm
cargo xtask codegen --stages 19
cargo xtask codegen --stages $TOFINO_STAGES

banner "Test"
sudo -E ./tools/veth_setup.sh
Expand Down
28 changes: 22 additions & 6 deletions asic/src/softnpu/table.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

use slog::{error, trace};
use softnpu_lib::{ManagementRequest, TableAdd, TableRemove};
Expand Down Expand Up @@ -31,6 +31,8 @@ const LOCAL_V6: &str = "ingress.local.local_v6";
const LOCAL_V4: &str = "ingress.local.local_v4";
const NAT_V4: &str = "ingress.nat.nat_v4";
const NAT_V6: &str = "ingress.nat.nat_v6";
const ATTACHED_SUBNET_V4: &str = "ingress.attached.attached_subnet_v4";
const ATTACHED_SUBNET_V6: &str = "ingress.attached.attached_subnet_v6";
const _NAT_ICMP_V6: &str = "ingress.nat.nat_icmp_v6";
const _NAT_ICMP_V4: &str = "ingress.nat.nat_icmp_v4";
const RESOLVER_V4: &str = "ingress.resolver.resolver_v4";
Expand All @@ -54,12 +56,16 @@ const ARP: &str = "pipe.Ingress.l3_router.Router4.Arp.tbl";
const DPD_MAC_REWRITE: &str = "pipe.Ingress.mac_rewrite.mac_rewrite";
const NAT_INGRESS4: &str = "pipe.Ingress.nat_ingress.ingress_ipv4";
const NAT_INGRESS6: &str = "pipe.Ingress.nat_ingress.ingress_ipv6";
const ATTACHED_SUBNET_INGRESS4: &str =
"pipe.Ingress.attached_subnet_ingress.attached_subnets_v4";
const ATTACHED_SUBNET_INGRESS6: &str =
"pipe.Ingress.attached_subnet_ingress.attached_subnets_v6";

// All tables are defined to be 1024 entries deep
const TABLE_SIZE: usize = 4096;

impl TableOps<Handle> for Table {
fn new(_hdl: &Handle, name: &str) -> AsicResult<Table> {
fn new(hdl: &Handle, name: &str) -> AsicResult<Table> {
// TODO just mapping sidecar.p4 things onto simplified sidecar-lite.p4
// things to get started.
let (id, dpd_id) = match name {
Expand All @@ -84,8 +90,16 @@ impl TableOps<Handle> for Table {
}
NAT_INGRESS4 => (Some(NAT_V4.into()), Some(NAT_INGRESS4.into())),
NAT_INGRESS6 => (Some(NAT_V6.into()), Some(NAT_INGRESS6.into())),
ATTACHED_SUBNET_INGRESS4 => (
Some(ATTACHED_SUBNET_V4.into()),
Some(ATTACHED_SUBNET_INGRESS4.into()),
),
ATTACHED_SUBNET_INGRESS6 => (
Some(ATTACHED_SUBNET_V6.into()),
Some(ATTACHED_SUBNET_INGRESS6.into()),
),
x => {
println!("TABLE NOT HANDLED {x}");
error!(hdl.log, "TABLE NOT HANDLED {x}");
(None, None)
}
};
Expand Down Expand Up @@ -382,7 +396,9 @@ impl TableOps<Handle> for Table {
("rewrite", params)
}
(NAT_INGRESS4, "forward_ipv4_to")
| (NAT_INGRESS6, "forward_ipv6_to") => {
| (NAT_INGRESS6, "forward_ipv6_to")
| (ATTACHED_SUBNET_INGRESS4, "forward_to_v4")
| (ATTACHED_SUBNET_INGRESS6, "forward_to_v6") => {
let mut target = Vec::new();
let mut vni = Vec::new();
let mut mac = Vec::new();
Expand Down Expand Up @@ -463,7 +479,7 @@ impl TableOps<Handle> for Table {
("forward_to_sled", params)
}
(tbl, x) => {
println!("ACTION NOT HANDLED {tbl} {x}");
error!(hdl.log, "ACTION NOT HANDLED {tbl} {x}");
return Ok(());
}
};
Expand Down Expand Up @@ -610,7 +626,7 @@ fn keyset_data(match_data: Vec<MatchEntryField>, table: &str) -> Vec<u8> {
MatchEntryValue::Lpm(x) => {
let mut data: Vec<u8> = Vec::new();
match table {
ROUTER_V4_IDX => {
ROUTER_V4_IDX | ATTACHED_SUBNET_V4 => {
// prefix for longest prefix match operation
// "dst_addr" => hdr.ipv4.dst: lpm => bit<32>
serialize_value_type_be(&x.prefix, &mut data);
Expand Down
26 changes: 26 additions & 0 deletions common/src/attached_subnet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// 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 2026 Oxide Computer Company

use oxnet::IpNet;
use std::fmt;

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::network::InstanceTarget;

/** represents an external subnet mapping */
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
pub struct AttachedSubnetEntry {
pub subnet: IpNet,
pub tgt: InstanceTarget,
}

impl fmt::Display for AttachedSubnetEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}->{}", self.subnet, self.tgt)
}
}
3 changes: 2 additions & 1 deletion common/src/lib.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

use std::collections::BTreeSet;
use std::convert::TryFrom;
Expand All @@ -11,6 +11,7 @@ use std::sync::Once;
use std::time::Duration;
use std::time::Instant;

pub mod attached_subnet;
pub mod counters;
pub mod logging;
pub mod nat;
Expand Down
89 changes: 3 additions & 86 deletions common/src/nat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,14 @@
// 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

use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr};

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::network::MacAddr;

/// A Geneve Virtual Network Identifier.
///
/// A Geneve VNI is a 24-bit value used to identify virtual networks
/// encapsulated using the Generic Network Virtualization Encapsulation (Geneve)
/// protocol (RFC 8926).
#[derive(
Clone,
Copy,
Debug,
Deserialize,
Eq,
Hash,
JsonSchema,
PartialEq,
PartialOrd,
Ord,
Serialize,
)]
#[serde(try_from = "u32")]
pub struct Vni(u32);

impl Vni {
const MAX_VNI: u32 = 0x00FF_FFFF;
const ERR_MSG: &'static str = "VNI out of 24-bit range";

/// Construct a new VNI, validating that it's a valid 24-bit value.
pub const fn new(vni: u32) -> Option<Self> {
// bool.then_some is not const, unforunately
if vni <= Self::MAX_VNI {
Some(Self(vni))
} else {
None
}
}

/// Return the VNI as a u32.
pub const fn as_u32(&self) -> u32 {
self.0
}
}

impl core::convert::TryFrom<u32> for Vni {
type Error = &'static str;

fn try_from(vni: u32) -> Result<Self, Self::Error> {
Self::new(vni).ok_or(Self::ERR_MSG)
}
}

impl core::str::FromStr for Vni {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.parse::<u32>().map(Vni::new) {
Err(_) | Ok(None) => Err(Self::ERR_MSG),
Ok(Some(vni)) => Ok(vni),
}
}
}

impl fmt::Display for Vni {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}

/** represents an internal NAT target */
#[derive(
Debug, Copy, Clone, Deserialize, Serialize, JsonSchema, Eq, PartialEq,
)]
pub struct NatTarget {
pub internal_ip: Ipv6Addr,
pub inner_mac: MacAddr,
pub vni: Vni,
}

impl fmt::Display for NatTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}/{}/{}", self.internal_ip, self.inner_mac, self.vni)
}
}
use crate::network::NatTarget;

/** represents an IPv6 NAT reservation */
#[derive(Debug, Copy, Clone, Deserialize, Serialize, JsonSchema)]
Expand Down Expand Up @@ -130,7 +47,7 @@ impl PartialEq for Ipv4Nat {

#[cfg(test)]
mod tests {
use super::Vni;
use crate::network::Vni;

#[test]
fn test_vni() {
Expand Down
Loading