Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
6 changes: 6 additions & 0 deletions illumos-utils/src/opte/illumos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use sled_agent_types::inventory::NetworkInterfaceKind;
use slog::Logger;
use slog::info;
use std::net::IpAddr;
use std::net::Ipv6Addr;

#[derive(thiserror::Error, Debug)]
pub enum Error {
Expand Down Expand Up @@ -70,6 +71,11 @@ pub enum Error {
"Tried to update attached subnets on non-existent port ({0}, {1:?})"
)]
AttachedSubnetUpdateMissingPort(uuid::Uuid, NetworkInterfaceKind),

#[error(
"address {0} is not within the underlay multicast subnet (ff04::/64)"
)]
Comment thread
zeeshanlakhani marked this conversation as resolved.
InvalidMcastUnderlay(Ipv6Addr),
}

/// Delete all xde devices on the system.
Expand Down
2 changes: 1 addition & 1 deletion illumos-utils/src/opte/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ use oxnet::IpNet;
use oxnet::Ipv4Net;
use oxnet::Ipv6Net;
pub use port::Port;
pub use port_manager::MulticastGroupCfg;
pub use port_manager::PortCreateParams;
pub use port_manager::PortManager;
pub use port_manager::PortTicket;
pub use sled_agent_types::multicast::MulticastGroupCfg;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::Ipv6Addr;
Expand Down
112 changes: 103 additions & 9 deletions illumos-utils/src/opte/non_illumos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,37 @@
// 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/.

//! Mock / dummy versions of the OPTE module, for non-illumos platforms
//! Mock / dummy versions of the OPTE module, for non-illumos platforms.
//!
//! Most methods are either `unimplemented!()` or silent no-ops.
//! Multicast subscribe/unsubscribe is an exception, as it maintains real
//! in-memory state because port manager tests assert on subscription contents.

use crate::addrobj::AddrObject;
use oxide_vpc::api::AddRouterEntryReq;
use oxide_vpc::api::ClearMcast2PhysReq;
use oxide_vpc::api::ClearMcastForwardingReq;
use oxide_vpc::api::ClearVirt2PhysReq;
use oxide_vpc::api::DelRouterEntryReq;
use oxide_vpc::api::DetachSubnetResp;
use oxide_vpc::api::Direction;
use oxide_vpc::api::DumpMcast2PhysResp;
use oxide_vpc::api::DumpMcastForwardingResp;
use oxide_vpc::api::DumpVirt2PhysResp;
use oxide_vpc::api::IpCfg;
use oxide_vpc::api::IpCidr;
use oxide_vpc::api::ListPortsResp;
use oxide_vpc::api::McastSubscribeReq;
use oxide_vpc::api::McastUnsubscribeReq;
use oxide_vpc::api::NoResp;
use oxide_vpc::api::PortInfo;
use oxide_vpc::api::RouterClass;
use oxide_vpc::api::RouterTarget;
use oxide_vpc::api::SetExternalIpsReq;
use oxide_vpc::api::SetFwRulesReq;
use oxide_vpc::api::SetMcast2PhysReq;
use oxide_vpc::api::SetMcastForwardingReq;
use oxide_vpc::api::SetVirt2PhysReq;
use oxide_vpc::api::SourceFilter;
use oxide_vpc::api::VpcCfg;
use sled_agent_types::inventory::NetworkInterfaceKind;
use slog::Logger;
Expand Down Expand Up @@ -76,6 +88,11 @@ pub enum Error {
"Tried to update attached subnets on non-existent port ({0}, {1:?})"
)]
AttachedSubnetUpdateMissingPort(uuid::Uuid, NetworkInterfaceKind),

#[error(
"address {0} is not within the underlay multicast subnet (ff04::/64)"
)]
Comment thread
zeeshanlakhani marked this conversation as resolved.
InvalidMcastUnderlay(std::net::Ipv6Addr),
}

pub fn initialize_xde_driver(
Expand Down Expand Up @@ -172,6 +189,8 @@ pub(crate) struct PortData {
pub port: PortInfo,
/// The routes for this port. This simulates the router layer.
pub routes: Vec<RouteInfo>,
/// Multicast group subscriptions: group IP → source filter.
pub mcast_subscriptions: HashMap<IpAddr, SourceFilter>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -237,7 +256,11 @@ impl Handle {
return Err(OpteError::DuplicatePort(entry.key().to_string()));
}
Entry::Vacant(entry) => {
entry.insert(PortData { port, routes: Vec::new() });
entry.insert(PortData {
port,
routes: Vec::new(),
mcast_subscriptions: HashMap::new(),
});
}
}
Ok(NO_RESPONSE)
Expand Down Expand Up @@ -270,14 +293,46 @@ impl Handle {
Ok(NO_RESPONSE)
}

/// Allow traffic to / from a CIDR block on a port.
pub fn allow_cidr(
/// Subscribe a port to a multicast group.
pub fn mcast_subscribe(
&self,
_: &str,
_: IpCidr,
_: Direction,
req: &McastSubscribeReq,
) -> Result<NoResp, OpteError> {
unimplemented!("Not yet used in tests")
let mut inner = opte_state().lock().unwrap();
let Some(port_data) = inner.ports.get_mut(&req.port_name) else {
return Err(OpteError::NoPort(req.port_name.clone()));
};
let group_ip: IpAddr = match req.group {
oxide_vpc::api::IpAddr::Ip4(v4) => {
std::net::Ipv4Addr::from(v4).into()
}
oxide_vpc::api::IpAddr::Ip6(v6) => {
std::net::Ipv6Addr::from(v6).into()
}
};
port_data.mcast_subscriptions.insert(group_ip, req.filter.clone());
Ok(NO_RESPONSE)
}

/// Unsubscribe a port from a multicast group.
pub fn mcast_unsubscribe(
&self,
req: &McastUnsubscribeReq,
) -> Result<NoResp, OpteError> {
let mut inner = opte_state().lock().unwrap();
let Some(port_data) = inner.ports.get_mut(&req.port_name) else {
return Err(OpteError::NoPort(req.port_name.clone()));
};
let group_ip: IpAddr = match req.group {
oxide_vpc::api::IpAddr::Ip4(v4) => {
std::net::Ipv4Addr::from(v4).into()
}
oxide_vpc::api::IpAddr::Ip6(v6) => {
std::net::Ipv6Addr::from(v6).into()
}
};
port_data.mcast_subscriptions.remove(&group_ip);
Ok(NO_RESPONSE)
}

/// Delete a router entry from a port.
Expand Down Expand Up @@ -323,6 +378,45 @@ impl Handle {
unimplemented!("Not yet used in tests")
}

/// Set a multicast-to-physical mapping.
pub fn set_m2p(&self, _: &SetMcast2PhysReq) -> Result<NoResp, OpteError> {
Ok(NO_RESPONSE)
}

/// Clear a multicast-to-physical mapping.
pub fn clear_m2p(
&self,
_: &ClearMcast2PhysReq,
) -> Result<NoResp, OpteError> {
Ok(NO_RESPONSE)
}

/// Set multicast forwarding for a port.
pub fn set_mcast_fwd(
&self,
_: &SetMcastForwardingReq,
) -> Result<NoResp, OpteError> {
Ok(NO_RESPONSE)
}

/// Clear multicast forwarding for a port.
pub fn clear_mcast_fwd(
&self,
_: &ClearMcastForwardingReq,
) -> Result<NoResp, OpteError> {
Ok(NO_RESPONSE)
}

/// Dump all multicast-to-physical mappings.
pub fn dump_m2p(&self) -> Result<DumpMcast2PhysResp, OpteError> {
Ok(DumpMcast2PhysResp { ip4: Vec::new(), ip6: Vec::new() })
}

/// Dump all multicast forwarding entries.
pub fn dump_mcast_fwd(&self) -> Result<DumpMcastForwardingResp, OpteError> {
Ok(DumpMcastForwardingResp { entries: Vec::new() })
}

/// List ports on the current system.
#[allow(dead_code)]
pub(crate) fn list_ports(&self) -> Result<ListPortsResp, OpteError> {
Expand Down
Loading
Loading