Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move underlay NICs back into H/W Classification #504

Merged
merged 33 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
173f5d3
WIP: Deliver packets via DLS client to escape S/W
FelixMcFelix Apr 24, 2024
94c5264
WIP: Put the promisc callback on the right mac client.
FelixMcFelix Apr 24, 2024
8ffd7c3
Merge branch 'master' into goodbye-all-of-classification
FelixMcFelix Jun 14, 2024
c34e257
Fixup for real!
FelixMcFelix Jun 14, 2024
b542fac
Found the bug.
FelixMcFelix Jun 17, 2024
dff4a58
Reorganisation, cleanup.
FelixMcFelix Jun 17, 2024
360955c
Clippy.
FelixMcFelix Jun 17, 2024
1da884e
Refactoring, newtype for DLS Link IDs
FelixMcFelix Jun 17, 2024
54182c9
Comment tweaks etc.
FelixMcFelix Jun 17, 2024
bb25fde
More commentary.
FelixMcFelix Jun 17, 2024
3dc09de
Should now have the correct attach/detach refs
FelixMcFelix Jun 19, 2024
c84ec5a
Simplify creation/cleanup.
FelixMcFelix Jun 19, 2024
7a4b068
Hmm.
FelixMcFelix Jun 19, 2024
0434f15
Dls, not Dld.
FelixMcFelix Jun 19, 2024
d7d416a
Cleanup.
FelixMcFelix Jun 19, 2024
303057b
Finalist tweaks
FelixMcFelix Jun 19, 2024
94819d5
Accidentally the wrong type.
FelixMcFelix Jun 20, 2024
bf35bf2
Review feedback: nits.
FelixMcFelix Jul 10, 2024
2e4d9c3
Merge branch 'master' into goodbye-all-of-classification
FelixMcFelix Jul 10, 2024
95a213d
Alloc/free dld_str_t from the kmem cache.
FelixMcFelix Aug 1, 2024
bb3cb41
Initial CTF reading from within opteadm.
FelixMcFelix Aug 1, 2024
d0d3986
Live verification of dld_str_s against runtime CTF
FelixMcFelix Aug 1, 2024
4fbcb4b
Remove some debug-fmt.
FelixMcFelix Aug 1, 2024
b682a16
Use live-running DLD (/system) rather than drv
FelixMcFelix Aug 2, 2024
984da1a
Update in tandem with stlouis#577.
FelixMcFelix Aug 6, 2024
dfb6ef4
Swap to upstreamed ctf-bindgen.
FelixMcFelix Aug 8, 2024
35b0187
Help CI along a little bit.
FelixMcFelix Aug 8, 2024
4074b11
Merge branch 'master' into goodbye-all-of-classification
FelixMcFelix Aug 8, 2024
b7e96a2
Back to `main` for ctf-bindgen
FelixMcFelix Aug 8, 2024
942a56e
Undo private access workarounds for ctf-bindgen
FelixMcFelix Aug 8, 2024
77ea7c8
Comment fixups.
FelixMcFelix Aug 8, 2024
ced9d52
No more reliance on `dld_str_t` internals
FelixMcFelix Aug 15, 2024
d3e5867
Uncork opte#532 while we're here.
FelixMcFelix Aug 15, 2024
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
2 changes: 1 addition & 1 deletion xde-tests/tests/loopback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn test_xde_loopback() -> Result<()> {
let topol = xde_tests::two_node_topology()?;

// Now we should be able to ping b from a on the overlay.
&topol.nodes[0]
_ = &topol.nodes[0]
.zone
.zone
.zexec(&format!("ping {}", &topol.nodes[1].port.ip()))?;
Expand Down
27 changes: 0 additions & 27 deletions xde/src/dls.rs

This file was deleted.

255 changes: 255 additions & 0 deletions xde/src/dls/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
// 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 2024 Oxide Computer Company

//! Safe abstractions around DLS public and private functions.
luqmana marked this conversation as resolved.
Show resolved Hide resolved

pub mod sys;

use crate::mac::mac_client_handle;
use crate::mac::MacClient;
use crate::mac::MacPerimeterHandle;
use crate::mac::MacTxFlags;
use crate::mac::MAC_DROP_ON_NO_DESC;
use core::ffi::CStr;
use core::fmt::Display;
use core::mem::MaybeUninit;
use core::ptr;
use illumos_sys_hdrs::c_int;
use illumos_sys_hdrs::datalink_id_t;
use illumos_sys_hdrs::uintptr_t;
use illumos_sys_hdrs::ENOENT;
use opte::engine::packet::Packet;
use opte::engine::packet::PacketState;
pub use sys::*;

/// An integer ID used by DLS to refer to a given link.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LinkId(datalink_id_t);

impl LinkId {
/// Request the link ID for a device using its name.
pub fn from_name(name: impl AsRef<CStr>) -> Result<Self, LinkError> {
let mut link_id = 0;

unsafe {
match dls_mgmt_get_linkid(name.as_ref().as_ptr(), &mut link_id) {
0 => Ok(LinkId(link_id)),
ENOENT => Err(LinkError::NotFound),
err => Err(LinkError::Other(err)),
}
}
}
}

impl From<LinkId> for datalink_id_t {
fn from(val: LinkId) -> Self {
val.0
}
}

/// Errors encountered while querying DLS for a `LinkId`.
pub enum LinkError {
NotFound,
Other(i32),
}

impl Display for LinkError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
LinkError::NotFound => write!(f, "link not found"),
LinkError::Other(e) => write!(f, "unknown error ({e})"),
}
}
}

/// A hold on an existing link managed by DLS.
#[derive(Debug)]
struct DlsLink {
inner: Option<DlsLinkInner>,
link: LinkId,
}

#[derive(Debug)]
struct DlsLinkInner {
dlp: *mut dls_link,
dlh: dls_dl_handle,
}

impl DlsLink {
/// Place a hold on an existing link.
fn hold(mph: &MacPerimeterHandle) -> Result<Self, c_int> {
let mut dlp = ptr::null_mut();
let mut dlh = ptr::null_mut();
let link = mph.link_id();

let res = unsafe { dls_devnet_hold(link.into(), &mut dlh) };
if res != 0 {
return Err(res);
}

let res = unsafe { dls_link_hold(dls_devnet_mac(dlh), &mut dlp) };
luqmana marked this conversation as resolved.
Show resolved Hide resolved
if res == 0 {
Ok(Self { inner: Some(DlsLinkInner { dlp, dlh }), link })
} else {
unsafe { dls_devnet_rele(dlh) };
Err(res)
}
}

/// Release a hold on a given link.
///
/// This operation requires that you acquire the MAC perimeter
/// for the target device.
fn release(mut self, mph: &MacPerimeterHandle) {
if let Some(inner) = self.inner.take() {
if mph.link_id() != self.link {
panic!("Tried to free link hold with the wrong MAC perimeter: saw {:?}, wanted {:?}",
mph.link_id(), self.link);
}
unsafe {
dls_link_rele(inner.dlp);
dls_devnet_rele(inner.dlh);
}
}
}

/// Convert a hold into a `DlsStream` for packet Rx/Tx.
fn open_stream(
mut self,
mph: &MacPerimeterHandle,
) -> Result<DlsStream, c_int> {
let Some(inner) = self.inner.as_ref() else {
panic!("attempted to open a DlsStream on freed link")
};

if mph.link_id() != self.link {
panic!("Tried to open stream with the wrong MAC perimeter: saw {:?}, wanted {:?}",
mph.link_id(), self.link);
}

let mut stream = MaybeUninit::zeroed();
let res =
unsafe { dls_open(inner.dlp, inner.dlh, stream.as_mut_ptr()) };
if res == 0 {
// DLP is held/consumed by dls_open.
_ = self.inner.take();
let dld_str = unsafe { stream.assume_init() };
Ok(DlsStream {
inner: Some(DlsStreamInner { dld_str }),
link: mph.link_id(),
}
.into())
} else {
self.release(mph);
Err(res)
}
}
}

impl Drop for DlsLink {
fn drop(&mut self) {
if self.inner.take().is_some() {
opte::engine::err!(
"dropped hold on link {:?} without releasing!!",
self.link
);
}
}
}

/// A DLS message stream on a target link, allowing packet
/// Rx and Tx.
#[derive(Debug)]
pub struct DlsStream {
inner: Option<DlsStreamInner>,
link: LinkId,
}

#[derive(Debug)]
struct DlsStreamInner {
dld_str: dld_str_s,
}

impl DlsStream {
pub fn open(link_id: LinkId) -> Result<Self, c_int> {
let perim = MacPerimeterHandle::from_linkid(link_id)?;
let link_handle = DlsLink::hold(&perim)?;
link_handle.open_stream(&perim)
}

/// Returns the ID of the link this stream belongs to.
pub fn link_id(&self) -> LinkId {
self.link
}

/// Send the [`Packet`] on this client, dropping if there is no
/// descriptor available
///
/// This function always consumes the [`Packet`].
///
/// XXX The underlying mac_tx() function accepts a packet chain,
/// but for now we pass only a single packet at a time.
pub fn tx_drop_on_no_desc(
&self,
pkt: Packet<impl PacketState>,
hint: uintptr_t,
flags: MacTxFlags,
) {
let Some(inner) = self.inner.as_ref() else {
// XXX: probably handle or signal an error here.
return;
};
// We must unwrap the raw `mblk_t` out of the `pkt` here,
// otherwise the mblk_t would be dropped at the end of this
// function along with `pkt`.
let mut raw_flags = flags.bits();
raw_flags |= MAC_DROP_ON_NO_DESC;
unsafe {
str_mdata_fastpath_put(
&inner.dld_str,
pkt.unwrap_mblk(),
hint,
raw_flags,
)
};
}
}

impl MacClient for DlsStream {
fn mac_client_handle(&self) -> Result<*mut mac_client_handle, c_int> {
let Some(inner) = self.inner.as_ref() else {
return Err(-1);
};

Ok(inner.dld_str.ds_mch)
}
}

impl Drop for DlsStream {
fn drop(&mut self) {
if let Some(mut inner) = self.inner.take() {
match MacPerimeterHandle::from_linkid(self.link) {
Ok(_perim) => unsafe {
// NOTE: this is reimplementing dld_str_detach
// but we're avoiding capab negotiation/disable and
// mac notify callbacks. Should we just come in through
// dld_open/dld_close/dld_wput? That would make it a bit
// weirder to set the promisc handle, and I don't know how
// this would interact with the existing (logical)
// STREAMS up to ip.
dls_close(&mut inner.dld_str);
dls_devnet_rele(inner.dld_str.ds_ddh)
},
Err(e) => opte::engine::err!(
"couldn't acquire MAC perimeter (err {}): \
dropped stream on link {:?} without releasing",
e,
self.link,
),
}
}
}
}
Loading