diff --git a/crates/opte-api/src/ip.rs b/crates/opte-api/src/ip.rs index 153f4733..c5285f20 100644 --- a/crates/opte-api/src/ip.rs +++ b/crates/opte-api/src/ip.rs @@ -380,6 +380,7 @@ impl FromStr for IpAddr { PartialOrd, Serialize, )] +#[repr(C)] pub struct Ipv4Addr { inner: [u8; 4], } @@ -554,6 +555,7 @@ impl Deref for Ipv4Addr { Serialize, Deserialize, )] +#[repr(C)] pub struct Ipv6Addr { inner: [u8; 16], } diff --git a/crates/opte-api/src/lib.rs b/crates/opte-api/src/lib.rs index 60b1c1d7..45cc4c80 100644 --- a/crates/opte-api/src/lib.rs +++ b/crates/opte-api/src/lib.rs @@ -47,7 +47,7 @@ pub use ulp::*; /// /// We rely on CI and the check-api-version.sh script to verify that /// this number is incremented anytime the oxide-api code changes. -pub const API_VERSION: u64 = 29; +pub const API_VERSION: u64 = 30; /// Major version of the OPTE package. pub const MAJOR_VERSION: u64 = 0; diff --git a/dtrace/common.h b/dtrace/common.h index 2797bf60..bb642d03 100644 --- a/dtrace/common.h +++ b/dtrace/common.h @@ -9,32 +9,32 @@ #define FLOW_FMT(svar, fvar) \ this->src_ip = (ipaddr_t *)alloca(4); \ this->dst_ip = (ipaddr_t *)alloca(4); \ - *this->src_ip = fvar->src_ip4; \ - *this->dst_ip = fvar->dst_ip4; \ + *this->src_ip = fvar->addrs.ip4.src; \ + *this->dst_ip = fvar->addrs.ip4.dst; \ svar = protos[fvar->proto]; \ svar = strjoin(svar, ","); \ svar = strjoin(svar, inet_ntoa(this->src_ip)); \ svar = strjoin(svar, ":"); \ - svar = strjoin(svar, lltostr(ntohs(fvar->src_port))); \ + svar = strjoin(svar, lltostr(fvar->src_port)); \ svar = strjoin(svar, ","); \ svar = strjoin(svar, inet_ntoa(this->dst_ip)); \ svar = strjoin(svar, ":"); \ - svar = strjoin(svar, lltostr(ntohs(fvar->dst_port))); + svar = strjoin(svar, lltostr(fvar->dst_port)); #define FLOW_FMT6(svar, fvar) \ this->src_ip6 = (in6_addr_t *)alloca(16); \ this->dst_ip6 = (in6_addr_t *)alloca(16); \ - *this->src_ip6 = fvar->src_ip6; \ - *this->dst_ip6 = fvar->dst_ip6; \ + *this->src_ip6 = fvar->addrs.ip6.src; \ + *this->dst_ip6 = fvar->addrs.ip6.dst; \ svar = protos[fvar->proto]; \ svar = strjoin(svar, ",["); \ svar = strjoin(svar, inet_ntoa6(this->src_ip6)); \ svar = strjoin(svar, "]:"); \ - svar = strjoin(svar, lltostr(ntohs(fvar->src_port))); \ + svar = strjoin(svar, lltostr(fvar->src_port)); \ svar = strjoin(svar, ",["); \ svar = strjoin(svar, inet_ntoa6(this->dst_ip6)); \ svar = strjoin(svar, "]:"); \ - svar = strjoin(svar, lltostr(ntohs(fvar->dst_port))); + svar = strjoin(svar, lltostr(fvar->dst_port)); #define ETH_FMT(svar, evar) \ svar = substr(lltostr(evar[0], 16), 2); \ @@ -55,3 +55,6 @@ * 2 = Outbound */ #define DIR_STR(dir) ((dir) == 1 ? "IN" : "OUT") + +#define EL_DELIMIT "->" +#define EL_FMT "->%s" diff --git a/dtrace/lib/common.d b/dtrace/lib/common.d index 80b657cd..e4fe26d0 100644 --- a/dtrace/lib/common.d +++ b/dtrace/lib/common.d @@ -2,14 +2,20 @@ #pragma D depends_on provider ip typedef struct flow_id_sdt_arg { - int af; - ipaddr_t src_ip4; - ipaddr_t dst_ip4; - in6_addr_t src_ip6; - in6_addr_t dst_ip6; + uint8_t proto; + uint16_t af; + union addrs { + struct { + ipaddr_t src; + ipaddr_t dst; + } ip4; + struct { + in6_addr_t src; + in6_addr_t dst; + } ip6; + } addrs; uint16_t src_port; uint16_t dst_port; - uint8_t proto; } flow_id_sdt_arg_t; typedef struct rule_match_sdt_arg { @@ -48,8 +54,8 @@ typedef struct opte_cmd_ioctl { } opte_cmd_ioctl_t; typedef struct derror_sdt_arg { - size_t len; - uint8_t truncated; - uint64_t data[2]; - char* entry[8]; + size_t len; + uint8_t truncated; + uint64_t data[2]; + char* entry[8]; } derror_sdt_arg_t; diff --git a/dtrace/opte-bad-packet.d b/dtrace/opte-bad-packet.d index 0b88c197..93574452 100644 --- a/dtrace/opte-bad-packet.d +++ b/dtrace/opte-bad-packet.d @@ -6,8 +6,7 @@ #include "common.h" #define HDR_FMT "%-12s %-3s %-18s %s\n" -#define LINE_FMT "%-12s %-3s 0x%-16p " -#define EL_FMT "->%s" +#define LINE_FMT "%-12s %-3s 0x%-16p %s[%d, %d]\n" BEGIN { printf(HDR_FMT, "PORT", "DIR", "MBLK", "MSG+DATA"); @@ -21,13 +20,13 @@ bad-packet { this->msgs = (derror_sdt_arg_t*) arg3; this->msg_len = this->msgs->len; this->data_len = arg4; + this->res = stringof(""); if (num >= 10) { printf(HDR_FMT, "PORT", "DIR", "MBLK", "MSG+DATA"); num = 0; } - printf(LINE_FMT, this->port, this->dir, this->mblk); num++; } @@ -36,51 +35,61 @@ bad-packet { bad-packet /this->msg_len > 0/ { - printf("%s", stringof(this->msgs->entry[0])); + this->res = strjoin(this->res, stringof(this->msgs->entry[0])); } bad-packet /this->msg_len > 1/ { - printf(EL_FMT, stringof(this->msgs->entry[1])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[1])); } bad-packet /this->msg_len > 2/ { - printf(EL_FMT, stringof(this->msgs->entry[2])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[2])); } bad-packet /this->msg_len > 3/ { - printf(EL_FMT, stringof(this->msgs->entry[3])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[3])); } bad-packet /this->msg_len > 4/ { - printf(EL_FMT, stringof(this->msgs->entry[4])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[4])); } bad-packet /this->msg_len > 5/ { - printf(EL_FMT, stringof(this->msgs->entry[5])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[5])); } bad-packet /this->msg_len > 6/ { - printf(EL_FMT, stringof(this->msgs->entry[6])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[6])); } bad-packet /this->msg_len > 7/ { - printf(EL_FMT, stringof(this->msgs->entry[7])); + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[7])); } bad-packet { - printf(" [%d, %d]\n", this->msgs->data[0], this->msgs->data[1]); + printf(LINE_FMT, + this->port, this->dir, this->mblk, + this->res, this->msgs->data[0], this->msgs->data[1] + ); } diff --git a/dtrace/opte-layer-process.d b/dtrace/opte-layer-process.d index cfb0d08d..59a7a4d7 100644 --- a/dtrace/opte-layer-process.d +++ b/dtrace/opte-layer-process.d @@ -23,7 +23,9 @@ layer-process-return { this->layer = stringof(arg2); this->flow_before = (flow_id_sdt_arg_t *)arg3; this->flow_after = (flow_id_sdt_arg_t *)arg4; - this->res = stringof(arg5); + this->msgs = (derror_sdt_arg_t*) arg5; + this->msg_len = this->msgs->len; + this->res = stringof(""); if (num >= 10) { printf(HDR_FMT, "PORT", "LAYER", "DIR", "FLOW BEFORE", @@ -38,6 +40,19 @@ layer-process-return { } } +layer-process-return +/this->msg_len > 0/ +{ + this->res = strjoin(this->res, stringof(this->msgs->entry[0])); +} + +layer-process-return +/this->msg_len > 1/ +{ + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[1])); +} + layer-process-return /this->af == AF_INET/ { FLOW_FMT(this->s_before, this->flow_before); FLOW_FMT(this->s_after, this->flow_after); diff --git a/dtrace/opte-port-process.d b/dtrace/opte-port-process.d index 314e7801..93b7cbc7 100644 --- a/dtrace/opte-port-process.d +++ b/dtrace/opte-port-process.d @@ -24,7 +24,9 @@ port-process-return { this->mp = (mblk_t *)arg5; /* If the result is a hairpin packet, then hp_mp is non-NULL. */ this->hp_mp = (mblk_t *)arg6; - this->res = stringof(arg7); + this->msgs = (derror_sdt_arg_t*) arg7; + this->msg_len = this->msgs->len; + this->res = stringof(""); if (num >= 10) { printf(HDR_FMT, "NAME", "DIR", "EPOCH", "FLOW BEFORE", @@ -39,6 +41,19 @@ port-process-return { } } +port-process-return +/this->msg_len > 0/ +{ + this->res = strjoin(this->res, stringof(this->msgs->entry[0])); +} + +port-process-return +/this->msg_len > 1/ +{ + this->res = strjoin(this->res, EL_DELIMIT); + this->res = strjoin(this->res, stringof(this->msgs->entry[1])); +} + port-process-return /this->af == AF_INET/ { FLOW_FMT(this->s_before, this->flow_before); FLOW_FMT(this->s_after, this->flow_after); @@ -55,4 +70,3 @@ port-process-return /this->af == AF_INET6/ { num++; } - diff --git a/lib/opte/src/d_error.rs b/lib/opte/src/d_error.rs index 9987b60e..a675a479 100644 --- a/lib/opte/src/d_error.rs +++ b/lib/opte/src/d_error.rs @@ -33,8 +33,8 @@ macro_rules! static_cstr { // XXX: I think we want some way of doing the whole thing in one big chunk // to prevent e.g. 4 dyn dispatches in a row. -/// A trait used for walking chains of errors which store useful data in -/// a leaf node. +/// A trait used for walking chains of errors (or other types -- mainly `enum`s) +/// which store useful data in a leaf node. pub trait DError { /// Provide the name of an error's discriminant. fn discriminant(&self) -> &'static CStr; @@ -48,16 +48,16 @@ pub trait DError { static_cstr!(EMPTY_STRING, b"\0"); -/// An error trace designed to be passed to a Dtrace handler, which contains +/// An string list designed to be passed to a DTrace handler, which contains /// the names of all `enum` discriminators encountered when resolving an error -/// as well as the data from a leaf node. +/// or other result-like enum, as well as the data from a leaf node. /// /// This wrapper cannot contain a null c_string pointer, so all entries are -/// safe to dereference from a dtrace script. Additionally, it has a fixed +/// safe to dereference from a DTrace script. Additionally, it has a fixed /// C-ABI representation to minimise the work needed to pass it as an SDT arg. #[derive(Debug)] #[repr(C)] -pub struct ErrorBlock { +pub struct LabelBlock { len: usize, more: bool, // XXX: Maybe we can move this to a generic? @@ -66,7 +66,7 @@ pub struct ErrorBlock { entries: [*const i8; L], } -impl ErrorBlock { +impl LabelBlock { /// Create storage to hold at most `L` static string entries. pub fn new() -> Self { Self { @@ -79,21 +79,23 @@ impl ErrorBlock { } } - /// Flatten a nested error into a static string list. + /// Flatten a nested type into a static string list. /// - /// This function will return an error if the provided `err` contains - /// too many entries to include within this `ErrorBlock`. - pub fn from_err(err: &dyn DError) -> Result, ErrorBlock> { - let mut out = ErrorBlock::new(); - - if out.append(err).is_err() { + /// This function will return an `Err` if the provided `val` contains + /// too many entries to include within this `LabelBlock`. + pub fn from_nested( + val: &dyn DError, + ) -> Result, LabelBlock> { + let mut out = LabelBlock::new(); + + if out.append(val).is_err() { Err(out) } else { Ok(out) } } - /// Push all layers (and data) of an error into a block. + /// Push all layers (and data) of a nested type into a block. pub fn append(&mut self, err: &dyn DError) -> Result<(), ()> { let mut top: Option<&dyn DError> = Some(err); while let Some(el) = top { @@ -122,7 +124,7 @@ impl ErrorBlock { /// Appends the top layer name of a given error. /// - /// Callers must ensure that pointee outlives this ErrorBlock. + /// Callers must ensure that pointee outlives this LabelBlock. pub unsafe fn append_name_raw<'a, 'b: 'a>( &'a mut self, err: &'b CStr, @@ -149,8 +151,8 @@ impl ErrorBlock { } /// Provides access to all stored [`CStr`]s. - pub fn entries<'a>(&'a self) -> ErrorBlockIter<'a, L> { - ErrorBlockIter { pos: 0, inner: self } + pub fn entries<'a>(&'a self) -> LabelBlockIter<'a, L> { + LabelBlockIter { pos: 0, inner: self } } /// Provides pointers to all stored [`CStr`]s. @@ -165,16 +167,16 @@ impl ErrorBlock { /// Return a pointer to this object for inclusion in an SDT. pub fn as_ptr(&self) -> *const Self { - self as *const ErrorBlock + self as *const LabelBlock } } -pub struct ErrorBlockIter<'a, const L: usize> { +pub struct LabelBlockIter<'a, const L: usize> { pos: usize, - inner: &'a ErrorBlock, + inner: &'a LabelBlock, } -impl<'a, const L: usize> Iterator for ErrorBlockIter<'a, L> { +impl<'a, const L: usize> Iterator for LabelBlockIter<'a, L> { type Item = &'static CStr; fn next(&mut self) -> Option { @@ -182,7 +184,7 @@ impl<'a, const L: usize> Iterator for ErrorBlockIter<'a, L> { return None; } - // SAFETY: ErrorBlock can only be constructed using 'static CStr + // SAFETY: LabelBlock can only be constructed using 'static CStr // entries, and defaults to be full of empty entries. // So any pointee is a valid static CStr. let out = unsafe { CStr::from_ptr(self.inner.entries[self.pos]) }; @@ -197,7 +199,7 @@ impl<'a, const L: usize> Iterator for ErrorBlockIter<'a, L> { } } -impl<'a, const L: usize> ExactSizeIterator for ErrorBlockIter<'a, L> { +impl<'a, const L: usize> ExactSizeIterator for LabelBlockIter<'a, L> { fn len(&self) -> usize { self.inner.len - self.pos } @@ -239,7 +241,7 @@ mod tests { #[test] fn name_and_data_storage() { let err = TestEnum::A; - let block: ErrorBlock<2> = ErrorBlock::from_err(&err).unwrap(); + let block: LabelBlock<2> = LabelBlock::from_nested(&err).unwrap(); let mut block_iter = block.entries(); assert_eq!(block_iter.len(), 1); assert_eq!(block_iter.next(), Some(A_C)); @@ -247,12 +249,12 @@ mod tests { assert_eq!(block_iter.next(), None); let err = TestEnum::B(TestChildEnum::NoData); - let block: ErrorBlock<2> = ErrorBlock::from_err(&err).unwrap(); + let block: LabelBlock<2> = LabelBlock::from_nested(&err).unwrap(); let names = block.entries().collect::>(); assert_eq!(&names[..], &[B_C, ND_C][..]); let err = TestEnum::B(TestChildEnum::Data { a: 0xab, b: 0xcd }); - let block: ErrorBlock<2> = ErrorBlock::from_err(&err).unwrap(); + let block: LabelBlock<2> = LabelBlock::from_nested(&err).unwrap(); let names = block.entries().collect::>(); assert_eq!(&names[..], &[B_C, D_C][..]); assert_eq!(block.data[0], 0xab); @@ -262,7 +264,7 @@ mod tests { #[test] fn name_truncation() { let err = TestEnum::B(TestChildEnum::NoData); - let block: ErrorBlock<1> = ErrorBlock::from_err(&err).unwrap_err(); + let block: LabelBlock<1> = LabelBlock::from_nested(&err).unwrap_err(); let mut block_iter = block.entries(); assert_eq!(block_iter.len(), 1); assert_eq!(block_iter.next(), Some(B_C)); diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index 1987ed29..4bd53d27 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -19,17 +19,12 @@ use alloc::string::String; use alloc::vec::Vec; use core::fmt; use core::num::NonZeroU32; +#[cfg(all(not(feature = "std"), not(test)))] +use illumos_sys_hdrs::uintptr_t; use opte_api::OpteError; use serde::de::DeserializeOwned; use serde::Serialize; -cfg_if! { - if #[cfg(all(not(feature = "std"), not(test)))] { - use illumos_sys_hdrs::uintptr_t; - use super::rule::flow_id_sdt_arg; - } -} - // XXX This really shouldn't be pub but for now we are leaking this // info for the purpose of testing until the Port API has support for // setting/getting TTL on a per Flow Table basis. @@ -229,16 +224,13 @@ fn flow_expired_probe( last_hit: Option, now: Option, ) { - last_hit.unwrap_or_default(); cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let arg = flow_id_sdt_arg::from(flowid); - unsafe { __dtrace_probe_flow__expired( port.as_ptr() as uintptr_t, name.as_ptr() as uintptr_t, - &arg as *const flow_id_sdt_arg as uintptr_t, + flowid, last_hit.and_then(|m| m.raw_millis()).unwrap_or_default() as usize, now.and_then(|m| m.raw_millis()).unwrap_or_default() as usize, ); @@ -332,7 +324,7 @@ extern "C" { pub fn __dtrace_probe_flow__expired( port: uintptr_t, layer: uintptr_t, - flowid: uintptr_t, + flowid: *const InnerFlowId, last_hit: uintptr_t, now: uintptr_t, ); @@ -341,7 +333,7 @@ extern "C" { dir: uintptr_t, port: uintptr_t, layer: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, epoch: uintptr_t, ); } @@ -355,8 +347,8 @@ impl Dump for () { #[cfg(test)] mod test { use super::*; - use crate::engine::headers::IpAddr; use crate::engine::ip4::Protocol; + use crate::engine::packet::AddrPair; use crate::engine::packet::FLOW_ID_DEFAULT; use core::time::Duration; @@ -365,10 +357,12 @@ mod test { #[test] fn flow_expired() { let flowid = InnerFlowId { - proto: Protocol::TCP, - src_ip: IpAddr::Ip4("192.168.2.10".parse().unwrap()), + proto: Protocol::TCP.into(), + addrs: AddrPair::V4 { + src: "192.168.2.10".parse().unwrap(), + dst: "76.76.21.21".parse().unwrap(), + }, src_port: 37890, - dst_ip: IpAddr::Ip4("76.76.21.21".parse().unwrap()), dst_port: 443, }; @@ -389,10 +383,12 @@ mod test { #[test] fn flow_clear() { let flowid = InnerFlowId { - proto: Protocol::TCP, - src_ip: IpAddr::Ip4("192.168.2.10".parse().unwrap()), + proto: Protocol::TCP.into(), + addrs: AddrPair::V4 { + src: "192.168.2.10".parse().unwrap(), + dst: "76.76.21.21".parse().unwrap(), + }, src_port: 37890, - dst_ip: IpAddr::Ip4("76.76.21.21".parse().unwrap()), dst_port: 443, }; diff --git a/lib/opte/src/engine/layer.rs b/lib/opte/src/engine/layer.rs index a1412b4f..bfdb053c 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -24,7 +24,6 @@ use super::packet::FLOW_ID_DEFAULT; use super::port::meta::ActionMeta; use super::port::Transforms; use super::rule; -use super::rule::flow_id_sdt_arg; use super::rule::ht_probe; use super::rule::Action; use super::rule::ActionDesc; @@ -33,6 +32,9 @@ use super::rule::Finalized; use super::rule::GenBtError; use super::rule::HdrTransformError; use super::rule::Rule; +use crate::d_error::DError; +#[cfg(all(not(feature = "std"), not(test)))] +use crate::d_error::LabelBlock; use crate::ddi::kstat; use crate::ddi::kstat::KStatNamed; use crate::ddi::kstat::KStatProvider; @@ -117,10 +119,15 @@ impl Display for DenyReason { } } -#[derive(Debug)] +// TODO: Represent `name` as joint C+RStr to implement fully. +#[derive(Debug, DError)] pub enum LayerResult { Allow, - Deny { name: &'static str, reason: DenyReason }, + Deny { + name: &'static str, + reason: DenyReason, + }, + #[leaf] Hairpin(Packet), HandlePkt, } @@ -569,7 +576,6 @@ impl Layer { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_arg = flow_id_sdt_arg::from(flow); let dir_c = CString::new(format!("{}", dir)).unwrap(); let msg_c = CString::new(format!("{:?}", err)).unwrap(); @@ -578,7 +584,7 @@ impl Layer { self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, dir_c.as_ptr() as uintptr_t, - &flow_arg as *const flow_id_sdt_arg as uintptr_t, + flow, msg_c.as_ptr() as uintptr_t, ); } @@ -605,7 +611,6 @@ impl Layer { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_arg = flow_id_sdt_arg::from(flow); let dir_c = CString::new(format!("{}", dir)).unwrap(); let msg_c = CString::new(format!("{:?}", err)).unwrap(); @@ -614,7 +619,7 @@ impl Layer { self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, dir_c.as_ptr() as uintptr_t, - &flow_arg as *const flow_id_sdt_arg as uintptr_t, + flow, msg_c.as_ptr() as uintptr_t, ); } @@ -646,15 +651,12 @@ impl Layer { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - - let ifid_arg = flow_id_sdt_arg::from(ifid); - unsafe { __dtrace_probe_layer__process__entry( dir as uintptr_t, self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, - &ifid_arg as *const flow_id_sdt_arg as uintptr_t, + ifid, ); } } else if #[cfg(feature = "usdt")] { @@ -681,25 +683,42 @@ impl Layer { if #[cfg(all(not(feature = "std"), not(test)))] { // XXX This would probably be better as separate probes; // for now this does the trick. - let res_str = match res { - Ok(v) => format!("{}", v), - Err(e) => format!("ERROR: {:?}", e), + let (eb, extra_str) = match res { + Ok(v @ LayerResult::Deny { name, reason }) => ( + LabelBlock::from_nested(v), + Some(format!("{{name: \"{name}\", reason: {reason:?}}}\0")) + ), + Ok(v) => (LabelBlock::from_nested(v), None), + // TODO: Handle the error types in a zero-cost way. + Err(e) => (Ok(LabelBlock::new()), Some(format!("ERROR: {:?}\0", e))), }; - let flow_b_arg = flow_id_sdt_arg::from(flow_before); - let flow_a_arg = flow_id_sdt_arg::from(flow_after); - let res_c = CString::new(res_str).unwrap(); + // Truncation is captured *in* the LabelBlock. + let mut eb = match eb { + Ok(block) => block, + Err(block) => block, + }; + + let extra_cstr = extra_str + .as_ref() + .and_then( + |v| core::ffi::CStr::from_bytes_until_nul(v.as_bytes()).ok() + ); unsafe { + if let Some(extra_cstr) = extra_cstr { + let _ = eb.append_name_raw(extra_cstr); + } __dtrace_probe_layer__process__return( dir as uintptr_t, self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, - &flow_b_arg as *const flow_id_sdt_arg as uintptr_t, - &flow_a_arg as *const flow_id_sdt_arg as uintptr_t, - res_c.as_ptr() as uintptr_t, + flow_before, + flow_after, + eb.as_ptr(), ); } + drop(extra_str); } else if #[cfg(feature = "usdt")] { let port_s = self.port_c.to_str().unwrap(); let flow_b_s = flow_before.to_string(); @@ -1460,14 +1479,12 @@ impl Layer { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_arg = flow_id_sdt_arg::from(flow_id); - unsafe { __dtrace_probe_rule__deny( self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, dir as uintptr_t, - &flow_arg as *const flow_id_sdt_arg as uintptr_t, + flow_id, ); } } else if #[cfg(feature = "usdt")] { @@ -1701,13 +1718,11 @@ impl<'a> RuleTable { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_id = flow_id_sdt_arg::from(flow_id); - let arg = rule_no_match_sdt_arg { port: port.as_ptr(), layer: layer.as_ptr(), dir: dir as uintptr_t, - flow_id: &flow_id, + flow_id, }; unsafe { @@ -1738,13 +1753,12 @@ impl<'a> RuleTable { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { let action_str = rule.action().to_string(); - let flow_id = flow_id_sdt_arg::from(flow_id); let action_str_c = CString::new(action_str).unwrap(); let arg = rule_match_sdt_arg { port: port.as_ptr(), layer: layer.as_ptr(), dir: dir as uintptr_t, - flow_id: &flow_id, + flow_id, rule_type: action_str_c.as_ptr(), }; @@ -1782,7 +1796,7 @@ extern "C" { port: uintptr_t, layer: uintptr_t, dir: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, msg: uintptr_t, ); @@ -1790,7 +1804,7 @@ extern "C" { port: uintptr_t, layer: uintptr_t, dir: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, msg: uintptr_t, ); @@ -1798,15 +1812,15 @@ extern "C" { dir: uintptr_t, port: uintptr_t, name: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, ); pub fn __dtrace_probe_layer__process__return( dir: uintptr_t, port: uintptr_t, name: uintptr_t, - flow_before: uintptr_t, - flow_after: uintptr_t, - res: uintptr_t, + flow_before: *const InnerFlowId, + flow_after: *const InnerFlowId, + res: *const LabelBlock<2>, ); pub fn __dtrace_probe_rule__match(arg: uintptr_t); @@ -1816,7 +1830,7 @@ extern "C" { port: uintptr_t, layer: uintptr_t, dir: uintptr_t, - flow: uintptr_t, + flow: *const InnerFlowId, ); } @@ -1825,7 +1839,7 @@ pub struct rule_match_sdt_arg { pub port: *const c_char, pub layer: *const c_char, pub dir: uintptr_t, - pub flow_id: *const flow_id_sdt_arg, + pub flow_id: *const InnerFlowId, pub rule_type: *const c_char, } @@ -1834,7 +1848,7 @@ pub struct rule_no_match_sdt_arg { pub port: *const c_char, pub layer: *const c_char, pub dir: uintptr_t, - pub flow_id: *const flow_id_sdt_arg, + pub flow_id: *const InnerFlowId, } #[cfg(test)] diff --git a/lib/opte/src/engine/nat.rs b/lib/opte/src/engine/nat.rs index 252af5d3..d51f3c22 100644 --- a/lib/opte/src/engine/nat.rs +++ b/lib/opte/src/engine/nat.rs @@ -156,7 +156,7 @@ impl StatefulAction for InboundNat { // registered to this port. Ok(AllowOrDeny::Allow(Arc::new(NatDesc { priv_ip: self.priv_ip, - external_ip: flow_id.dst_ip, + external_ip: flow_id.dst_ip(), verifier: self.verifier.clone(), }))) } diff --git a/lib/opte/src/engine/packet.rs b/lib/opte/src/engine/packet.rs index a65ca27c..098acbd1 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -31,6 +31,8 @@ use super::headers::IpAddr; use super::headers::IpMeta; use super::headers::UlpHdr; use super::headers::UlpMeta; +use super::headers::AF_INET; +use super::headers::AF_INET6; use super::icmp::IcmpHdr; use super::icmp::IcmpHdrError; use super::icmp::IcmpMeta; @@ -41,6 +43,7 @@ use super::ip4::Ipv4Hdr; use super::ip4::Ipv4HdrError; use super::ip4::Ipv4Meta; use super::ip4::Protocol; +use super::ip6::Ipv6Addr; use super::ip6::Ipv6Hdr; use super::ip6::Ipv6HdrError; use super::ip6::Ipv6Meta; @@ -83,10 +86,9 @@ cfg_if! { pub static MBLK_MAX_SIZE: usize = u16::MAX as usize; pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { - proto: Protocol::Unknown(255), - src_ip: IpAddr::Ip4(Ipv4Addr::ANY_ADDR), + proto: 255, + addrs: AddrPair::V4 { src: Ipv4Addr::ANY_ADDR, dst: Ipv4Addr::ANY_ADDR }, src_port: 0, - dst_ip: IpAddr::Ip4(Ipv4Addr::ANY_ADDR), dst_port: 0, }; @@ -97,12 +99,11 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { /// /// NOTE: This should not be defined in `opte`. Rather, the engine /// should be generic in regards to the flow identifier, and it should -/// be up to the `NetowrkImpl` to define it. +/// be up to the `NetworkImpl` to define it. #[derive( Clone, Copy, Debug, - Default, Deserialize, Eq, Hash, @@ -111,26 +112,83 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { PartialOrd, Serialize, )] +#[repr(C, align(4))] pub struct InnerFlowId { - pub proto: Protocol, - pub src_ip: IpAddr, + // Using a `u8` here for `proto` hides the enum repr from SDTs. + pub proto: u8, + // We could also theoretically get to a 38B packing if we reduce + // AddrPair's repr from `u16` to `u8`. However, on the dtrace/illumos + // side `union addrs` is 4B aligned -- in6_addr_t has a 4B alignment. + // So, this layout has to match that constraint -- placing addrs at + // offset 0x2 with `u16` discriminant sets up 4B alignment for the + // enum variant data (and this struct itself is 4B aligned). + pub addrs: AddrPair, pub src_port: u16, - pub dst_ip: IpAddr, pub dst_port: u16, } +impl Default for InnerFlowId { + fn default() -> Self { + FLOW_ID_DEFAULT + } +} + +#[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + Hash, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] +#[repr(C, u16)] +pub enum AddrPair { + V4 { src: Ipv4Addr, dst: Ipv4Addr } = AF_INET as u16, + V6 { src: Ipv6Addr, dst: Ipv6Addr } = AF_INET6 as u16, +} + +impl AddrPair { + pub fn mirror(self) -> Self { + match self { + Self::V4 { src, dst } => Self::V4 { src: dst, dst: src }, + Self::V6 { src, dst } => Self::V6 { src: dst, dst: src }, + } + } +} + impl InnerFlowId { /// Swap IP source and destination as well as ULP port source and /// destination. pub fn mirror(self) -> Self { Self { proto: self.proto, - src_ip: self.dst_ip, + addrs: self.addrs.mirror(), src_port: self.dst_port, - dst_ip: self.src_ip, dst_port: self.src_port, } } + + pub fn src_ip(&self) -> IpAddr { + match self.addrs { + AddrPair::V4 { src, .. } => src.into(), + AddrPair::V6 { src, .. } => src.into(), + } + } + + pub fn dst_ip(&self) -> IpAddr { + match self.addrs { + AddrPair::V4 { dst, .. } => dst.into(), + AddrPair::V6 { dst, .. } => dst.into(), + } + } + + pub fn protocol(&self) -> Protocol { + Protocol::from(self.proto) + } } impl Display for InnerFlowId { @@ -138,25 +196,25 @@ impl Display for InnerFlowId { write!( f, "{}:{}:{}:{}:{}", - self.proto, self.src_ip, self.src_port, self.dst_ip, self.dst_port, + self.protocol(), + self.src_ip(), + self.src_port, + self.dst_ip(), + self.dst_port, ) } } impl From<&PacketMeta> for InnerFlowId { fn from(meta: &PacketMeta) -> Self { - let (proto, src_ip, dst_ip) = match &meta.inner.ip { + let (proto, addrs) = match &meta.inner.ip { Some(IpMeta::Ip4(ip4)) => { - (ip4.proto, IpAddr::Ip4(ip4.src), IpAddr::Ip4(ip4.dst)) + (ip4.proto, AddrPair::V4 { src: ip4.src, dst: ip4.dst }) } Some(IpMeta::Ip6(ip6)) => { - (ip6.proto, IpAddr::Ip6(ip6.src), IpAddr::Ip6(ip6.dst)) + (ip6.proto, AddrPair::V6 { src: ip6.src, dst: ip6.dst }) } - None => ( - Protocol::Unknown(255), - IpAddr::Ip4(Ipv4Addr::from([0; 4])), - IpAddr::Ip4(Ipv4Addr::from([0; 4])), - ), + None => (Protocol::Unknown(255), FLOW_ID_DEFAULT.addrs), }; let (src_port, dst_port) = meta @@ -170,7 +228,7 @@ impl From<&PacketMeta> for InnerFlowId { }) .unwrap_or((0, 0)); - InnerFlowId { proto, src_ip, src_port, dst_ip, dst_port } + InnerFlowId { proto: proto.into(), addrs, src_port, dst_port } } } diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 614a7fcf..ad6d215d 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -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 2023 Oxide Computer Company +// Copyright 2024 Oxide Computer Company //! A virtual switch port. @@ -29,8 +29,6 @@ use super::packet::Packet; use super::packet::PacketMeta; use super::packet::Parsed; use super::packet::FLOW_ID_DEFAULT; -#[cfg(all(not(feature = "std"), not(test)))] -use super::rule::flow_id_sdt_arg; use super::rule::Action; use super::rule::Finalized; use super::rule::HdrTransform; @@ -43,6 +41,9 @@ use super::tcp_state::TcpFlowState; use super::tcp_state::TcpFlowStateError; use super::HdlPktAction; use super::NetworkImpl; +use crate::d_error::DError; +#[cfg(all(not(feature = "std"), not(test)))] +use crate::d_error::LabelBlock; use crate::ddi::kstat; use crate::ddi::kstat::KStatNamed; use crate::ddi::kstat::KStatProvider; @@ -127,11 +128,15 @@ impl From for ProcessError { /// * Hairpin: One of the layers has determined that it should reply /// directly with a packet of its own. In this case the original /// packet is dropped. -#[derive(Debug)] +#[derive(Debug, DError)] pub enum ProcessResult { Bypass, - Drop { reason: DropReason }, + #[leaf] + Drop { + reason: DropReason, + }, Modified, + #[leaf] Hairpin(Packet), } @@ -855,14 +860,13 @@ impl Port { let mblk_addr = pkt.map(|p| p.mblk_addr()).unwrap_or_default(); cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_arg = flow_id_sdt_arg::from(flow); let msg_arg = CString::new(msg).unwrap(); unsafe { __dtrace_probe_tcp__err( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - &flow_arg as *const flow_id_sdt_arg as uintptr_t, + flow, mblk_addr, msg_arg.as_ptr() as uintptr_t, ); @@ -1416,13 +1420,11 @@ impl Port { ) { cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_arg = flow_id_sdt_arg::from(flow); - unsafe { __dtrace_probe_port__process__entry( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - &flow_arg as *const flow_id_sdt_arg as uintptr_t, + flow, epoch as uintptr_t, pkt.mblk_addr(), ); @@ -1447,17 +1449,34 @@ impl Port { res: &result::Result, ) { let flow_after = pkt.flow(); + cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_b_arg = flow_id_sdt_arg::from(flow_before); - let flow_a_arg = flow_id_sdt_arg::from(flow_after); + // XXX This would probably be better as separate probes; // for now this does the trick. - let res_str = match res { - Ok(v) => format!("{:?}", v), - Err(e) => format!("ERROR: {:?}", e), + let (eb, extra_str) = match res { + Ok(v @ ProcessResult::Drop { reason }) => ( + LabelBlock::from_nested(v), + Some(format!("{reason:?}\0")) + ), + Ok(v) => (LabelBlock::from_nested(v), None), + // TODO: Handle the error types in a zero-cost way. + Err(e) => (Ok(LabelBlock::new()), Some(format!("ERROR: {:?}\0", e))), }; - let res_arg = CString::new(res_str).unwrap(); + + // Truncation is captured *in* the LabelBlock. + let mut eb = match eb { + Ok(block) => block, + Err(block) => block, + }; + + let extra_cstr = extra_str + .as_ref() + .and_then( + |v| core::ffi::CStr::from_bytes_until_nul(v.as_bytes()).ok() + ); + let hp_pkt_ptr = match res { Ok(ProcessResult::Hairpin(hp)) => { hp.mblk_addr() @@ -1466,18 +1485,20 @@ impl Port { }; unsafe { + if let Some(extra_cstr) = extra_cstr { + let _ = eb.append_name_raw(extra_cstr); + } __dtrace_probe_port__process__return( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - &flow_b_arg as *const flow_id_sdt_arg as uintptr_t, - &flow_a_arg as *const flow_id_sdt_arg as uintptr_t, + flow_before, + flow_after, epoch as uintptr_t, pkt.mblk_addr(), hp_pkt_ptr, - res_arg.as_ptr() as uintptr_t, + eb.as_ptr(), ); } - } else if #[cfg(feature = "usdt")] { let flow_b_s = flow_before.to_string(); let flow_a_s = flow_after.to_string(); @@ -1845,13 +1866,11 @@ impl Port { ) { cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let ufid_arg = flow_id_sdt_arg::from(ufid); - unsafe { __dtrace_probe_uft__hit( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - &ufid_arg as *const flow_id_sdt_arg as uintptr_t, + ufid, epoch as uintptr_t, last_hit.raw_millis().unwrap_or_default() as usize ); @@ -2322,13 +2341,11 @@ impl Port { ) { cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let ufid_arg = flow_id_sdt_arg::from(ufid); - unsafe { __dtrace_probe_uft__invalidate( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - &ufid_arg as *const flow_id_sdt_arg as uintptr_t, + ufid, epoch as uintptr_t, ); } @@ -2361,13 +2378,11 @@ impl Port { fn uft_tcp_closed_probe(&self, dir: Direction, ufid: &InnerFlowId) { cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let ufid_arg = flow_id_sdt_arg::from(ufid); - unsafe { __dtrace_probe_uft__tcp__closed( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - &ufid_arg as *const flow_id_sdt_arg as uintptr_t, + ufid, ); } } else if #[cfg(feature = "usdt")] { @@ -2649,44 +2664,44 @@ extern "C" { pub fn __dtrace_probe_port__process__entry( dir: uintptr_t, port: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, epoch: uintptr_t, pkt: uintptr_t, ); pub fn __dtrace_probe_port__process__return( dir: uintptr_t, port: uintptr_t, - flow_before: uintptr_t, - flow_after: uintptr_t, + flow_before: *const InnerFlowId, + flow_after: *const InnerFlowId, epoch: uintptr_t, pkt: uintptr_t, hp_pkt: uintptr_t, - res: uintptr_t, + err_b: *const LabelBlock<2>, ); pub fn __dtrace_probe_tcp__err( dir: uintptr_t, port: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, pkt: uintptr_t, msg: uintptr_t, ); pub fn __dtrace_probe_uft__hit( dir: uintptr_t, port: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, epoch: uintptr_t, last_hit: uintptr_t, ); pub fn __dtrace_probe_uft__invalidate( dir: uintptr_t, port: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, epoch: uintptr_t, ); pub fn __dtrace_probe_uft__tcp__closed( dir: uintptr_t, port: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, ); } diff --git a/lib/opte/src/engine/print.rs b/lib/opte/src/engine/print.rs index 3878e08f..dc506385 100644 --- a/lib/opte/src/engine/print.rs +++ b/lib/opte/src/engine/print.rs @@ -200,16 +200,13 @@ pub fn print_lft_flow( flow_id: &InnerFlowId, flow_entry: &ActionDescEntryDump, ) -> std::io::Result<()> { - // For those types with custom Display implementations we need to - // first format in into a String before passing it to println in - // order for the format specification to be honored. writeln!( t, "{}\t{}\t{}\t{}\t{}\t{}\t{}", - flow_id.proto.to_string(), - flow_id.src_ip.to_string(), + flow_id.protocol(), + flow_id.src_ip(), flow_id.src_port, - flow_id.dst_ip.to_string(), + flow_id.dst_ip(), flow_id.dst_port, flow_entry.hits, flow_entry.summary, @@ -227,16 +224,13 @@ pub fn print_uft_flow( flow_id: &InnerFlowId, flow_entry: &UftEntryDump, ) -> std::io::Result<()> { - // For those types with custom Display implementations we need to - // first format in into a String before passing it to println in - // order for the format specification to be honored. writeln!( t, "{}\t{}\t{}\t{}\t{}\t{}\t{}", - flow_id.proto.to_string(), - flow_id.src_ip.to_string(), + flow_id.protocol(), + flow_id.src_ip(), flow_id.src_port, - flow_id.dst_ip.to_string(), + flow_id.dst_ip(), flow_id.dst_port, flow_entry.hits, flow_entry.summary, diff --git a/lib/opte/src/engine/rule.rs b/lib/opte/src/engine/rule.rs index 8e6a4fde..0b2fe198 100644 --- a/lib/opte/src/engine/rule.rs +++ b/lib/opte/src/engine/rule.rs @@ -9,13 +9,11 @@ use super::ether::EtherMeta; use super::ether::EtherMod; use super::flow_table::StateSummary; -use super::headers; use super::headers::EncapMeta; use super::headers::EncapMod; use super::headers::EncapPush; use super::headers::HeaderAction; use super::headers::HeaderActionError; -use super::headers::IpAddr; use super::headers::IpMeta; use super::headers::IpMod; use super::headers::IpPush; @@ -305,72 +303,30 @@ extern "C" { pub fn __dtrace_probe_ht__run(arg: uintptr_t); } -#[repr(C)] -pub struct flow_id_sdt_arg { - af: i32, - src_ip4: u32, - dst_ip4: u32, - src_ip6: [u8; 16], - dst_ip6: [u8; 16], - src_port: u16, - dst_port: u16, - proto: u8, -} - -impl From<&InnerFlowId> for flow_id_sdt_arg { - fn from(ifid: &InnerFlowId) -> Self { - // Consumers expect all data to be presented as it would be - // traveling across the network. - let (af, src_ip4, src_ip6) = match ifid.src_ip { - IpAddr::Ip4(ip4) => (headers::AF_INET, ip4.to_be(), [0; 16]), - IpAddr::Ip6(ip6) => (headers::AF_INET6, 0, ip6.bytes()), - }; - - let (dst_ip4, dst_ip6) = match ifid.dst_ip { - IpAddr::Ip4(ip4) => (ip4.to_be(), [0; 16]), - IpAddr::Ip6(ip6) => (0, ip6.bytes()), - }; - - flow_id_sdt_arg { - af, - src_ip4, - dst_ip4, - src_ip6, - dst_ip6, - src_port: ifid.src_port.to_be(), - dst_port: ifid.dst_port.to_be(), - proto: u8::from(ifid.proto), - } - } -} - #[repr(C)] pub struct ht_run_sdt_arg { pub port: *const c_char, pub loc: *const c_char, pub dir: uintptr_t, - pub flow_id_before: *const flow_id_sdt_arg, - pub flow_id_after: *const flow_id_sdt_arg, + pub flow_id_before: *const InnerFlowId, + pub flow_id_after: *const InnerFlowId, } pub fn ht_probe( port: &CString, loc: &CStr, dir: Direction, - before: &InnerFlowId, - after: &InnerFlowId, + flow_id_before: &InnerFlowId, + flow_id_after: &InnerFlowId, ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_id_before = flow_id_sdt_arg::from(before); - let flow_id_after = flow_id_sdt_arg::from(after); - let arg = ht_run_sdt_arg { port: port.as_ptr(), loc: loc.as_ptr(), dir: dir as uintptr_t, - flow_id_before: &flow_id_before, - flow_id_after: &flow_id_after, + flow_id_before, + flow_id_after, }; unsafe { @@ -381,14 +337,14 @@ pub fn ht_probe( } else if #[cfg(feature = "usdt")] { let port_s = port.to_str().unwrap(); let loc_c = loc.to_str().unwrap(); - let before_s = before.to_string(); - let after_s = after.to_string(); + let before_s = flow_id_before.to_string(); + let after_s = flow_id_after.to_string(); crate::opte_provider::ht__run!( || (port_s, loc_c, dir, before_s, after_s) ); } else { - let (..) = (port, loc, dir, before, after); + let (..) = (port, loc, dir, flow_id_before, flow_id_after); } } } diff --git a/lib/opte/src/engine/snat.rs b/lib/opte/src/engine/snat.rs index 07adb1c8..39b2ed85 100644 --- a/lib/opte/src/engine/snat.rs +++ b/lib/opte/src/engine/snat.rs @@ -306,8 +306,9 @@ where _meta: &mut ActionMeta, ) -> GenDescResult { let priv_port = flow_id.src_port; - let is_icmp = flow_id.proto == T::MESSAGE_PROTOCOL; - let pool = match flow_id.proto { + let proto = flow_id.protocol(); + let is_icmp = proto == T::MESSAGE_PROTOCOL; + let pool = match proto { Protocol::TCP => &self.tcp_pool, Protocol::UDP => &self.udp_pool, _ if is_icmp => &self.icmp_pool, diff --git a/lib/opte/src/engine/tcp_state.rs b/lib/opte/src/engine/tcp_state.rs index e2cdece3..62423648 100644 --- a/lib/opte/src/engine/tcp_state.rs +++ b/lib/opte/src/engine/tcp_state.rs @@ -13,15 +13,10 @@ use super::tcp::TcpState; use core::ffi::CStr; use core::fmt; use core::fmt::Display; +#[cfg(all(not(feature = "std"), not(test)))] +use illumos_sys_hdrs::uintptr_t; use opte_api::Direction; -cfg_if! { - if #[cfg(all(not(feature = "std"), not(test)))] { - use illumos_sys_hdrs::uintptr_t; - use super::rule::flow_id_sdt_arg; - } -} - /// An error processing a TCP flow. #[derive(Clone, Copy, Debug, PartialEq)] pub enum TcpFlowStateError { @@ -587,13 +582,12 @@ impl TcpFlowState { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_id = flow_id_sdt_arg::from(flow_id); let state = tcp_flow_state_sdt_arg::from(self); unsafe { __dtrace_probe_tcp__flow__drop( port.as_ptr() as uintptr_t, - &flow_id as *const flow_id_sdt_arg as uintptr_t, + flow_id, &state as *const tcp_flow_state_sdt_arg as uintptr_t, dir as uintptr_t, flags as uintptr_t, @@ -626,11 +620,10 @@ impl TcpFlowState { ) { cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { - let flow_id = flow_id_sdt_arg::from(flow_id); unsafe { __dtrace_probe_tcp__flow__state( port.as_ptr() as uintptr_t, - &flow_id as *const flow_id_sdt_arg as uintptr_t, + flow_id, self.tcp_state as uintptr_t, new_state as uintptr_t, ); @@ -681,14 +674,14 @@ impl From<&TcpFlowState> for tcp_flow_state_sdt_arg { extern "C" { pub fn __dtrace_probe_tcp__flow__state( port: uintptr_t, - flow_id: uintptr_t, + flow_id: *const InnerFlowId, prev_state: uintptr_t, curr_state: uintptr_t, ); pub fn __dtrace_probe_tcp__flow__drop( port: uintptr_t, - flow_id: uintptr_t, + flow_id: *const InnerFlowId, flow_state: uintptr_t, dir: uintptr_t, flags: uintptr_t, diff --git a/lib/oxide-vpc/src/engine/gateway/mod.rs b/lib/oxide-vpc/src/engine/gateway/mod.rs index f76478d4..eeb90889 100644 --- a/lib/oxide-vpc/src/engine/gateway/mod.rs +++ b/lib/oxide-vpc/src/engine/gateway/mod.rs @@ -254,7 +254,7 @@ impl MetaAction for VpcMeta { flow: &InnerFlowId, action_meta: &mut ActionMeta, ) -> ModMetaResult { - match self.vpc_mappings.ip_to_vni(&flow.dst_ip) { + match self.vpc_mappings.ip_to_vni(&flow.dst_ip()) { Some(vni) => { action_meta .insert(ACTION_META_VNI.to_string(), vni.to_string()); diff --git a/lib/oxide-vpc/src/engine/overlay.rs b/lib/oxide-vpc/src/engine/overlay.rs index 31c00ece..730ac41e 100644 --- a/lib/oxide-vpc/src/engine/overlay.rs +++ b/lib/oxide-vpc/src/engine/overlay.rs @@ -238,7 +238,7 @@ impl StaticAction for EncapAction { let phys_target = match target { RouterTargetInternal::InternetGateway => { - match self.v2b.get(&flow_id.dst_ip) { + match self.v2b.get(&flow_id.dst_ip()) { Some(phys) => { // Hash the packet onto a route target. This is a very // rudimentary mechanism. Should level-up to an ECMP @@ -290,7 +290,7 @@ impl StaticAction for EncapAction { }, RouterTargetInternal::VpcSubnet(_) => { - match self.v2p.get(&flow_id.dst_ip) { + match self.v2p.get(&flow_id.dst_ip()) { Some(phys) => PhysNet { ether: phys.ether, ip: phys.ip, diff --git a/xde/src/xde.rs b/xde/src/xde.rs index 0f12b8d1..22f0cab3 100644 --- a/xde/src/xde.rs +++ b/xde/src/xde.rs @@ -47,7 +47,7 @@ use opte::api::OpteCmdIoctl; use opte::api::OpteError; use opte::api::SetXdeUnderlayReq; use opte::api::XDE_IOC_OPTE_CMD; -use opte::d_error::ErrorBlock; +use opte::d_error::LabelBlock; use opte::ddi::sync::KMutex; use opte::ddi::sync::KMutexType; use opte::ddi::sync::KRwLock; @@ -61,6 +61,7 @@ use opte::engine::headers::IpAddr; use opte::engine::ioctl::{self as api}; use opte::engine::ip6::Ipv6Addr; use opte::engine::packet::Initialized; +use opte::engine::packet::InnerFlowId; use opte::engine::packet::Packet; use opte::engine::packet::PacketError; use opte::engine::packet::Parsed; @@ -127,12 +128,12 @@ extern "C" { port: uintptr_t, dir: uintptr_t, mp: uintptr_t, - err_b: uintptr_t, + err_b: *const LabelBlock<8>, data_len: uintptr_t, ); pub fn __dtrace_probe_guest__loopback( mp: uintptr_t, - flow: uintptr_t, + flow: *const InnerFlowId, src_port: uintptr_t, dst_port: uintptr_t, ); @@ -160,8 +161,8 @@ fn bad_packet_parse_probe( Some(name) => name.as_c_str(), }; - // Truncation is captured *in* the ErrorBlock. - let block = match ErrorBlock::<8>::from_err(err) { + // Truncation is captured *in* the LabelBlock. + let block = match LabelBlock::<8>::from_nested(err) { Ok(block) => block, Err(block) => block, }; @@ -171,7 +172,7 @@ fn bad_packet_parse_probe( port_str.as_ptr() as uintptr_t, dir as uintptr_t, mp as uintptr_t, - block.as_ptr() as uintptr_t, + block.as_ptr(), 4, ) }; @@ -187,7 +188,7 @@ fn bad_packet_probe( None => c"unknown", Some(name) => name.as_c_str(), }; - let mut eb = ErrorBlock::<8>::new(); + let mut eb = LabelBlock::<8>::new(); unsafe { let _ = eb.append_name_raw(msg); @@ -195,7 +196,7 @@ fn bad_packet_probe( port_str.as_ptr() as uintptr_t, dir as uintptr_t, mp as uintptr_t, - eb.as_ptr() as uintptr_t, + eb.as_ptr(), 8, ) }; @@ -1340,14 +1341,10 @@ unsafe extern "C" fn xde_mc_unicst( } fn guest_loopback_probe(pkt: &Packet, src: &XdeDev, dst: &XdeDev) { - use opte::engine::rule::flow_id_sdt_arg; - - let fid_arg = flow_id_sdt_arg::from(pkt.flow()); - unsafe { __dtrace_probe_guest__loopback( pkt.mblk_addr(), - &fid_arg as *const flow_id_sdt_arg as uintptr_t, + pkt.flow(), src.port.name_cstr().as_ptr() as uintptr_t, dst.port.name_cstr().as_ptr() as uintptr_t, )