Skip to content
Draft
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
128 changes: 58 additions & 70 deletions crates/api-core/src/test_support/mac_address_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,122 +15,110 @@
* limitations under the License.
*/

use std::sync::atomic::{AtomicUsize, Ordering};

use carbide_utils::test_support::mac_address_pool as mock_mac_pool;
use mac_address::MacAddress;
pub use mock_mac_pool::MacAddressPoolConfig;

pub const DPU_OOB_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig = MacAddressPoolConfig {
start: [0x11, 0x11, 0x11, 0x11, 0x0, 0x0],
length: 65536,
};

pub const DPU_BMC_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig = MacAddressPoolConfig {
start: [0x11, 0x11, 0x22, 0x22, 0x0, 0x0],
length: 65536,
};

pub const HOST_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig = MacAddressPoolConfig {
start: [0x22, 0x22, 0x11, 0x11, 0x0, 0x0],
length: 65536,
};

pub const HOST_BMC_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig = MacAddressPoolConfig {
start: [0x22, 0x22, 0x22, 0x22, 0x0, 0x0],
length: 65536,
};

pub const HOST_NON_DPU_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig = MacAddressPoolConfig {
start: [0x33, 0x33, 0x11, 0x11, 0x0, 0x0],
length: 65536,
};

pub const EXPECTED_SWITCH_BMC_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig =
MacAddressPoolConfig {
start: [0x44, 0x44, 0x11, 0x11, 0x0, 0x0],
length: 65536,
};

#[derive(Copy, Clone, Debug)]
pub struct MacAddressPoolConfig {
/// The first mac address in the pool as a byte array
pub start: [u8; 6],
/// The amount of addresses in the pool
pub length: usize,
}
pub const EXPECTED_POWER_SHELF_BMC_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig =
MacAddressPoolConfig {
start: [0x44, 0x44, 0x22, 0x22, 0x0, 0x0],
length: 65536,
};

pub const EXPECTED_SWITCH_NVOS_MAC_ADDRESS_POOL_CONFIG: MacAddressPoolConfig =
MacAddressPoolConfig {
start: [0x44, 0x44, 0x33, 0x33, 0x0, 0x0],
length: 65536,
};

#[derive(Debug)]
pub struct MacAddressPool {
/// Defines which addresses are available in the pool
config: MacAddressPoolConfig,
/// How many addresses have already been allocated
used: AtomicUsize,
inner: mock_mac_pool::MacAddressPool,
}

impl MacAddressPool {
pub fn new(config: MacAddressPoolConfig) -> Self {
Self {
config,
used: AtomicUsize::new(0),
inner: mock_mac_pool::MacAddressPool::new(config),
}
}

/// Allocates a unique MAC address from the pool
///
/// Will panic once the pool is depleted
pub fn allocate(&self) -> MacAddress {
let offset = self.used.fetch_add(1, Ordering::SeqCst);
if offset >= self.config.length {
panic!("Mac address pool with config {:?} is depleted", self.config);
}

let mut u64_address = to_u64_be(self.config.start);
u64_address += offset as u64;

let mut bytes = [0u8; 6];
// The MAC address is stored by `to_u64_be` stored in the last 6 bytes
bytes.copy_from_slice(&u64_address.to_be_bytes()[2..8]);

MacAddress::new(bytes)
self.inner
.allocate()
.unwrap_or_else(|error| panic!("{error}"))
}

/// Returns whether an address is part of the pool
pub fn contains(&self, address: MacAddress) -> bool {
let a = to_u64_be(address.bytes());
let min = to_u64_be(self.config.start);

(min..min + self.config.length as u64).contains(&a)
self.inner.contains(address)
}
}

lazy_static::lazy_static! {
/// Pool of DPU MAC addresses
pub static ref DPU_OOB_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x11, 0x11, 0x11, 0x11, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(DPU_OOB_MAC_ADDRESS_POOL_CONFIG);

/// Pool of DPU BMC MAC addresses
pub static ref DPU_BMC_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x11, 0x11, 0x22, 0x22, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(DPU_BMC_MAC_ADDRESS_POOL_CONFIG);

/// Pool of Host MAC addresses
pub static ref HOST_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x22, 0x22, 0x11, 0x11, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(HOST_MAC_ADDRESS_POOL_CONFIG);

/// Pool of Host BMC MAC addresses
pub static ref HOST_BMC_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x22, 0x22, 0x22, 0x22, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(HOST_BMC_MAC_ADDRESS_POOL_CONFIG);

/// Pool of Host non-DPU MAC addresses
pub static ref HOST_NON_DPU_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x33, 0x33, 0x11, 0x11, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(HOST_NON_DPU_MAC_ADDRESS_POOL_CONFIG);

/// Pool of Expected Switch BMC MAC addresses
pub static ref EXPECTED_SWITCH_BMC_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x44, 0x44, 0x11, 0x11, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(EXPECTED_SWITCH_BMC_MAC_ADDRESS_POOL_CONFIG);

/// Pool of Expected Power Shelf BMC MAC addresses
pub static ref EXPECTED_POWER_SHELF_BMC_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x44, 0x44, 0x22, 0x22, 0x0, 0x0],
length: 65536,
});
MacAddressPool::new(EXPECTED_POWER_SHELF_BMC_MAC_ADDRESS_POOL_CONFIG);

/// Pool of Expected Switch NVOS MAC addresses
pub static ref EXPECTED_SWITCH_NVOS_MAC_ADDRESS_POOL: MacAddressPool =
MacAddressPool::new(MacAddressPoolConfig {
start: [0x44, 0x44, 0x33, 0x33, 0x0, 0x0],
length: 65536,
});
}

fn to_u64_be(bytes: [u8; 6]) -> u64 {
u64::from_be_bytes([
0, 0, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
])
MacAddressPool::new(EXPECTED_SWITCH_NVOS_MAC_ADDRESS_POOL_CONFIG);
}
57 changes: 56 additions & 1 deletion crates/api-core/src/tests/mac_address_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,13 @@

use mac_address::MacAddress;

use crate::test_support::mac_address_pool::{MacAddressPool, MacAddressPoolConfig};
use crate::test_support::mac_address_pool::{
DPU_BMC_MAC_ADDRESS_POOL_CONFIG, DPU_OOB_MAC_ADDRESS_POOL_CONFIG,
EXPECTED_POWER_SHELF_BMC_MAC_ADDRESS_POOL_CONFIG, EXPECTED_SWITCH_BMC_MAC_ADDRESS_POOL_CONFIG,
EXPECTED_SWITCH_NVOS_MAC_ADDRESS_POOL_CONFIG, HOST_BMC_MAC_ADDRESS_POOL_CONFIG,
HOST_MAC_ADDRESS_POOL_CONFIG, HOST_NON_DPU_MAC_ADDRESS_POOL_CONFIG, MacAddressPool,
MacAddressPoolConfig,
};

#[test]
fn allocate_addresses() {
Expand Down Expand Up @@ -64,3 +70,52 @@ fn depleted_pool_panics() {
);
pool.allocate();
}

#[test]
fn configured_ranges_do_not_overlap() {
for (left_index, (left_name, left_config)) in pool_configs().iter().enumerate() {
for (right_name, right_config) in pool_configs().iter().skip(left_index + 1) {
assert!(
!ranges_overlap(*left_config, *right_config),
"{left_name} overlaps {right_name}"
);
}
}
}

fn pool_configs() -> [(&'static str, MacAddressPoolConfig); 8] {
[
("dpu_oob", DPU_OOB_MAC_ADDRESS_POOL_CONFIG),
("dpu_bmc", DPU_BMC_MAC_ADDRESS_POOL_CONFIG),
("host", HOST_MAC_ADDRESS_POOL_CONFIG),
("host_bmc", HOST_BMC_MAC_ADDRESS_POOL_CONFIG),
("host_non_dpu", HOST_NON_DPU_MAC_ADDRESS_POOL_CONFIG),
(
"expected_switch_bmc",
EXPECTED_SWITCH_BMC_MAC_ADDRESS_POOL_CONFIG,
),
(
"expected_power_shelf_bmc",
EXPECTED_POWER_SHELF_BMC_MAC_ADDRESS_POOL_CONFIG,
),
(
"expected_switch_nvos",
EXPECTED_SWITCH_NVOS_MAC_ADDRESS_POOL_CONFIG,
),
]
}

fn ranges_overlap(left: MacAddressPoolConfig, right: MacAddressPoolConfig) -> bool {
let left_start = to_u64_be(left.start);
let left_end = left_start + left.length as u64;
let right_start = to_u64_be(right.start);
let right_end = right_start + right.length as u64;

left_start < right_end && right_start < left_end
}

fn to_u64_be(bytes: [u8; 6]) -> u64 {
u64::from_be_bytes([
0, 0, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
])
}
8 changes: 7 additions & 1 deletion crates/api-integration-tests/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use std::sync::Arc;
use std::time::{self, Duration};

use ::carbide_utils::HostPortPair;
use ::machine_a_tron::{BmcMockRegistry, HostMachineHandle, MachineATronConfig, MachineConfig};
use ::machine_a_tron::{
BmcMockRegistry, HostMachineHandle, MachineATronConfig, MachineConfig, MockMacAddressPoolConfig,
};
use api_test_helper::{
IntegrationTestEnvironment, domain, instance, machine, metrics, subnet, tenant, utils, vpc,
vpc_prefix,
Expand Down Expand Up @@ -914,6 +916,10 @@ where
api_refresh_interval: Duration::from_millis(500),
mock_bmc_ssh_server: false,
mock_bmc_ssh_port: None,
mock_mac_address_pool: MockMacAddressPoolConfig {
base_mac_address: "02:ff:00:00:00:10".parse().unwrap(),
length: 65536,
},
};

let (machine_handles, _mat_handle) = api_test_helper::machine_a_tron::run_local(
Expand Down
2 changes: 2 additions & 0 deletions crates/api-test-helper/src/machine_a_tron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub async fn run_local(
desired_firmware
);

let mock_mac_pool = Arc::new(app_config.mock_mac_pool());
let app_context = Arc::new(MachineATronContext {
bmc_registration_mode: if let Some(bmc_address_registry) = bmc_address_registry.as_ref() {
BmcRegistrationMode::BackingInstance(bmc_address_registry.clone())
Expand All @@ -87,6 +88,7 @@ pub async fn run_local(
api_throttler,
desired_firmware_versions: desired_firmware,
forge_api_client,
mock_mac_pool,
});

let mat = MachineATron::new(app_context.clone());
Expand Down
4 changes: 3 additions & 1 deletion crates/bmc-mock/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ authors.workspace = true
[dependencies]
bmc-vendor = { path = "../bmc-vendor" }
carbide-rpc = { path = "../rpc", default-features = false }
carbide-utils = { path = "../utils", default-features = false }
carbide-utils = { path = "../utils", default-features = false, features = [
"test-support",
] }

arc-swap = { workspace = true }
axum = { workspace = true }
Expand Down
3 changes: 3 additions & 0 deletions crates/bmc-mock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ pub mod test_support;
pub mod tls;

pub use bmc_state::{BmcEvent, BmcState};
pub use carbide_utils::test_support::mac_address_pool::{
MacAddressPool, MacAddressPoolConfig as MockMacAddressPoolConfig, MacAddressPoolError,
};
pub use combined_server::{CombinedServer, ListenerOrAddress};
pub use machine_info::{
DpuFirmwareVersions, DpuMachineInfo, DpuSettings, HostMachineInfo, MachineInfo,
Expand Down
Loading