From d5d247951308dc268bbad46c2da42a47dcbf5dd1 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Mon, 4 Mar 2024 17:15:01 +0000 Subject: [PATCH 01/18] Perf: rework InnerFlowId with a C ABI repr --- dtrace/common.h | 8 +-- dtrace/lib/common.d | 12 ++-- lib/opte/src/engine/flow_table.rs | 27 ++++--- lib/opte/src/engine/layer.rs | 34 +++------ lib/opte/src/engine/nat.rs | 2 +- lib/opte/src/engine/packet.rs | 89 ++++++++++++++++++----- lib/opte/src/engine/port.rs | 27 ++----- lib/opte/src/engine/print.rs | 8 +-- lib/opte/src/engine/rule.rs | 95 ++++++++++++------------- lib/opte/src/engine/tcp_state.rs | 15 ++-- lib/oxide-vpc/src/engine/gateway/mod.rs | 2 +- lib/oxide-vpc/src/engine/overlay.rs | 4 +- xde/src/xde.rs | 6 +- 13 files changed, 169 insertions(+), 160 deletions(-) diff --git a/dtrace/common.h b/dtrace/common.h index 2797bf60..0b628e18 100644 --- a/dtrace/common.h +++ b/dtrace/common.h @@ -9,8 +9,8 @@ #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->ip4[0]; \ + *this->dst_ip = fvar->ip4[1]; \ svar = protos[fvar->proto]; \ svar = strjoin(svar, ","); \ svar = strjoin(svar, inet_ntoa(this->src_ip)); \ @@ -24,8 +24,8 @@ #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->ip6[0]; \ + *this->dst_ip6 = fvar->ip6[1]; \ svar = protos[fvar->proto]; \ svar = strjoin(svar, ",["); \ svar = strjoin(svar, inet_ntoa6(this->src_ip6)); \ diff --git a/dtrace/lib/common.d b/dtrace/lib/common.d index 606dc161..8d5fe9b4 100644 --- a/dtrace/lib/common.d +++ b/dtrace/lib/common.d @@ -2,14 +2,14 @@ #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; + uint16_t proto; + uint8_t af; + union addrs { + ipaddr_t ip4[2]; + in6_addr_t ip6[2]; + }; uint16_t src_port; uint16_t dst_port; - uint8_t proto; } flow_id_sdt_arg_t; typedef struct rule_match_sdt_arg { diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index 1987ed29..86d38c69 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. @@ -232,13 +227,11 @@ fn flow_expired_probe( 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 as *const _ as uintptr_t, 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, ); @@ -355,8 +348,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; @@ -366,9 +359,11 @@ mod test { fn flow_expired() { let flowid = InnerFlowId { proto: Protocol::TCP, - src_ip: IpAddr::Ip4("192.168.2.10".parse().unwrap()), + 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, }; @@ -390,9 +385,11 @@ mod test { fn flow_clear() { let flowid = InnerFlowId { proto: Protocol::TCP, - src_ip: IpAddr::Ip4("192.168.2.10".parse().unwrap()), + 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..42a9ae7f 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; @@ -569,7 +568,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 +576,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 as *const _ as uintptr_t, msg_c.as_ptr() as uintptr_t, ); } @@ -605,7 +603,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 +611,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 as *const _ as uintptr_t, msg_c.as_ptr() as uintptr_t, ); } @@ -646,15 +643,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 as *const _ as uintptr_t, ); } } else if #[cfg(feature = "usdt")] { @@ -685,18 +679,15 @@ impl Layer { Ok(v) => format!("{}", v), Err(e) => format!("ERROR: {:?}", 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(); - unsafe { __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, + flow_before as *const _ as uintptr_t, + flow_after as *const _ as uintptr_t, res_c.as_ptr() as uintptr_t, ); } @@ -1460,14 +1451,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 as *const _ as uintptr_t, ); } } else if #[cfg(feature = "usdt")] { @@ -1701,13 +1690,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 +1725,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(), }; @@ -1825,7 +1811,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 +1820,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 646942a8..fbef0ca1 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -30,6 +30,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; @@ -40,6 +42,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; @@ -82,9 +85,8 @@ 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), + addrs: AddrPair::V4 { src: Ipv4Addr::ANY_ADDR, dst: Ipv4Addr::ANY_ADDR }, src_port: 0, - dst_ip: IpAddr::Ip4(Ipv4Addr::ANY_ADDR), dst_port: 0, }; @@ -100,7 +102,6 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { Clone, Copy, Debug, - Default, Deserialize, Eq, Hash, @@ -109,26 +110,80 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { PartialOrd, Serialize, )] +// pub struct InnerFlowId { +// pub proto: Protocol, +// pub src_ip: IpAddr, +// pub src_port: u16, +// pub dst_ip: IpAddr, +// pub dst_port: u16, +// } +#[repr(C)] pub struct InnerFlowId { + // XXX: if we store proto as `u8`, we get size down to 38B. pub proto: Protocol, - pub src_ip: IpAddr, + 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(u8)] +pub enum AddrPair { + V4 { src: Ipv4Addr, dst: Ipv4Addr } = AF_INET as u8, + V6 { src: Ipv6Addr, dst: Ipv6Addr } = AF_INET6 as u8, +} + +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(), + } + } } impl Display for InnerFlowId { @@ -136,25 +191,25 @@ impl Display for InnerFlowId { write!( f, "{}:{}:{}:{}:{}", - self.proto, self.src_ip, self.src_port, self.dst_ip, self.dst_port, + self.proto, + 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 @@ -168,7 +223,7 @@ impl From<&PacketMeta> for InnerFlowId { }) .unwrap_or((0, 0)); - InnerFlowId { proto, src_ip, src_port, dst_ip, dst_port } + InnerFlowId { proto, addrs, src_port, dst_port } } } diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 92e8eb78..314526e3 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -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; @@ -855,14 +853,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 as *const _ as uintptr_t, mblk_addr, msg_arg.as_ptr() as uintptr_t, ); @@ -1400,13 +1397,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 as *const _ as uintptr_t, epoch as uintptr_t, pkt.mblk_addr(), ); @@ -1433,8 +1428,6 @@ impl Port { 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 { @@ -1453,8 +1446,8 @@ impl Port { __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 as *const _ as uintptr_t, + &flow_after as *const _ as uintptr_t, epoch as uintptr_t, pkt.mblk_addr(), hp_pkt_ptr, @@ -1861,13 +1854,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 as *const _ as uintptr_t, epoch as uintptr_t, last_hit.raw_millis().unwrap_or_default() as usize ); @@ -2334,13 +2325,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 as *const _ as uintptr_t, epoch as uintptr_t, ); } @@ -2373,13 +2362,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 as *const _ as uintptr_t, ); } } else if #[cfg(feature = "usdt")] { diff --git a/lib/opte/src/engine/print.rs b/lib/opte/src/engine/print.rs index 3878e08f..ce08061c 100644 --- a/lib/opte/src/engine/print.rs +++ b/lib/opte/src/engine/print.rs @@ -207,9 +207,9 @@ pub fn print_lft_flow( t, "{}\t{}\t{}\t{}\t{}\t{}\t{}", flow_id.proto.to_string(), - flow_id.src_ip.to_string(), + flow_id.src_ip().to_string(), flow_id.src_port, - flow_id.dst_ip.to_string(), + flow_id.dst_ip().to_string(), flow_id.dst_port, flow_entry.hits, flow_entry.summary, @@ -234,9 +234,9 @@ pub fn print_uft_flow( t, "{}\t{}\t{}\t{}\t{}\t{}\t{}", flow_id.proto.to_string(), - flow_id.src_ip.to_string(), + flow_id.src_ip().to_string(), flow_id.src_port, - flow_id.dst_ip.to_string(), + flow_id.dst_ip().to_string(), 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..e03822ba 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,69 @@ 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 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 { @@ -388,7 +383,7 @@ pub fn ht_probe( || (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/tcp_state.rs b/lib/opte/src/engine/tcp_state.rs index e2cdece3..708b152c 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 as *const _ as uintptr_t, &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 as *const _ as uintptr_t, self.tcp_state as uintptr_t, new_state as 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 b0c1f014..711c7f8f 100644 --- a/lib/oxide-vpc/src/engine/overlay.rs +++ b/lib/oxide-vpc/src/engine/overlay.rs @@ -237,7 +237,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 @@ -289,7 +289,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 d2446795..5c0980c2 100644 --- a/xde/src/xde.rs +++ b/xde/src/xde.rs @@ -1307,14 +1307,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() as *const _ as uintptr_t, src.port.name_cstr().as_ptr() as uintptr_t, dst.port.name_cstr().as_ptr() as uintptr_t, ) From 48b831d10ccb87935d02f0ab45a2b21b6f885ba6 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Tue, 12 Mar 2024 13:49:23 +0000 Subject: [PATCH 02/18] Fix compile of bad USDT. --- lib/opte/src/engine/rule.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/opte/src/engine/rule.rs b/lib/opte/src/engine/rule.rs index e03822ba..6e14c3bb 100644 --- a/lib/opte/src/engine/rule.rs +++ b/lib/opte/src/engine/rule.rs @@ -376,8 +376,8 @@ 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) From cbbe56811a0ad970f62390663397798a4e5cfedc Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Tue, 12 Mar 2024 13:52:12 +0000 Subject: [PATCH 03/18] Temporarily disable miscompile-y probes --- lib/opte/src/engine/flow_table.rs | 2 +- lib/opte/src/engine/port.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index 86d38c69..dabda1ef 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -127,7 +127,7 @@ where } pub fn expire(&mut self, flowid: &InnerFlowId) { - flow_expired_probe(&self.port_c, &self.name_c, flowid, None, None); + // flow_expired_probe(&self.port_c, &self.name_c, flowid, None, None); self.map.remove(flowid); } diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 50e8663c..9200eb63 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -2366,10 +2366,10 @@ impl Port { ) { if let Some(ufid_in) = ufid_in { data.uft_in.remove(ufid_in); - self.uft_tcp_closed_probe(Direction::In, ufid_in); + // self.uft_tcp_closed_probe(Direction::In, ufid_in); } data.uft_out.remove(ufid_out); - self.uft_tcp_closed_probe(Direction::Out, ufid_out); + // self.uft_tcp_closed_probe(Direction::Out, ufid_out); } fn uft_tcp_closed_probe(&self, dir: Direction, ufid: &InnerFlowId) { From d84fba7109a1e5324c860f9a40c6b84bd99aab2f Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Tue, 12 Mar 2024 14:18:52 +0000 Subject: [PATCH 04/18] ...Oops. --- lib/opte/src/engine/flow_table.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index dabda1ef..ccacd285 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -141,13 +141,13 @@ where self.map.retain(|flowid, entry| { if self.policy.is_expired(entry, now) { - flow_expired_probe( - port_c, - name_c, - flowid, - Some(entry.last_hit), - Some(now), - ); + // flow_expired_probe( + // port_c, + // name_c, + // flowid, + // Some(entry.last_hit), + // Some(now), + // ); expired.push(f(entry.state())); return false; } From 4de9c4a80707a2231d7fd4f2ae65b5ca51498939 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Wed, 13 Mar 2024 11:30:54 +0000 Subject: [PATCH 05/18] DTrace script fixes, trying to understand odd behaviour. --- dtrace/common.h | 16 ++++++------- dtrace/lib/common.d | 6 ++--- lib/opte/src/engine/flow_table.rs | 4 ++-- lib/opte/src/engine/layer.rs | 10 ++++---- lib/opte/src/engine/packet.rs | 28 ++++++++++------------ lib/opte/src/engine/rule.rs | 39 ------------------------------- lib/opte/src/engine/snat.rs | 5 ++-- 7 files changed, 34 insertions(+), 74 deletions(-) diff --git a/dtrace/common.h b/dtrace/common.h index 0b628e18..c412b405 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->ip4[0]; \ - *this->dst_ip = fvar->ip4[1]; \ + *this->src_ip = fvar->addrs.ip4[0]; \ + *this->dst_ip = fvar->addrs.ip4[1]; \ 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->ip6[0]; \ - *this->dst_ip6 = fvar->ip6[1]; \ + *this->src_ip6 = fvar->addrs.ip6[0]; \ + *this->dst_ip6 = fvar->addrs.ip6[1]; \ 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); \ diff --git a/dtrace/lib/common.d b/dtrace/lib/common.d index d9602fa9..83c519bd 100644 --- a/dtrace/lib/common.d +++ b/dtrace/lib/common.d @@ -2,12 +2,12 @@ #pragma D depends_on provider ip typedef struct flow_id_sdt_arg { - uint16_t proto; - uint8_t af; + uint8_t proto; + uint16_t af; union addrs { ipaddr_t ip4[2]; in6_addr_t ip6[2]; - }; + } addrs; uint16_t src_port; uint16_t dst_port; } flow_id_sdt_arg_t; diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index ccacd285..85483594 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -358,7 +358,7 @@ mod test { #[test] fn flow_expired() { let flowid = InnerFlowId { - proto: Protocol::TCP, + proto: Protocol::TCP.into(), addrs: AddrPair::V4 { src: "192.168.2.10".parse().unwrap(), dst: "76.76.21.21".parse().unwrap(), @@ -384,7 +384,7 @@ mod test { #[test] fn flow_clear() { let flowid = InnerFlowId { - proto: Protocol::TCP, + proto: Protocol::TCP.into(), addrs: AddrPair::V4 { src: "192.168.2.10".parse().unwrap(), dst: "76.76.21.21".parse().unwrap(), diff --git a/lib/opte/src/engine/layer.rs b/lib/opte/src/engine/layer.rs index 42a9ae7f..e9e55e8d 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -671,6 +671,8 @@ impl Layer { flow_after: &InnerFlowId, res: &result::Result, ) { + // opte::engine::err!("are we stable tables? {:p}", flow_after); + // opte::engine::err!("are we stabler tables? {:?}", flow_after); cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { // XXX This would probably be better as separate probes; @@ -686,8 +688,8 @@ impl Layer { dir as uintptr_t, self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, - flow_before as *const _ as uintptr_t, - flow_after as *const _ as uintptr_t, + flow_before, + flow_after, res_c.as_ptr() as uintptr_t, ); } @@ -1790,8 +1792,8 @@ extern "C" { dir: uintptr_t, port: uintptr_t, name: uintptr_t, - flow_before: uintptr_t, - flow_after: uintptr_t, + flow_before: *const InnerFlowId, + flow_after: *const InnerFlowId, res: uintptr_t, ); diff --git a/lib/opte/src/engine/packet.rs b/lib/opte/src/engine/packet.rs index 9be86d4d..0260e7d3 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -86,7 +86,7 @@ cfg_if! { pub static MBLK_MAX_SIZE: usize = u16::MAX as usize; pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { - proto: Protocol::Unknown(255), + proto: 255, addrs: AddrPair::V4 { src: Ipv4Addr::ANY_ADDR, dst: Ipv4Addr::ANY_ADDR }, src_port: 0, dst_port: 0, @@ -99,7 +99,7 @@ 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, @@ -112,17 +112,13 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { PartialOrd, Serialize, )] -// pub struct InnerFlowId { -// pub proto: Protocol, -// pub src_ip: IpAddr, -// pub src_port: u16, -// pub dst_ip: IpAddr, -// pub dst_port: u16, -// } #[repr(C)] pub struct InnerFlowId { - // XXX: if we store proto as `u8`, we get size down to 38B. - pub proto: Protocol, + // Using a `u8` here for `proto` hides the enum repr from SDTs, + // but we need to have a `u16` discriminant for the IPs to set up + // 4B alignment on inaddr6_t on the dtrace side (so we lose out + // on the possibility of 38B packing). + pub proto: u8, pub addrs: AddrPair, pub src_port: u16, pub dst_port: u16, @@ -146,10 +142,10 @@ impl Default for InnerFlowId { PartialOrd, Serialize, )] -#[repr(u8)] +#[repr(u16)] pub enum AddrPair { - V4 { src: Ipv4Addr, dst: Ipv4Addr } = AF_INET as u8, - V6 { src: Ipv6Addr, dst: Ipv6Addr } = AF_INET6 as u8, + V4 { src: Ipv4Addr, dst: Ipv4Addr } = AF_INET as u16, + V6 { src: Ipv6Addr, dst: Ipv6Addr } = AF_INET6 as u16, } impl AddrPair { @@ -225,7 +221,7 @@ impl From<&PacketMeta> for InnerFlowId { }) .unwrap_or((0, 0)); - InnerFlowId { proto, addrs, src_port, dst_port } + InnerFlowId { proto: proto.into(), addrs, src_port, dst_port } } } @@ -1474,7 +1470,7 @@ impl Packet { } /// Return a reference to the flow ID of this packet. - #[inline] + // #[inline] pub fn flow(&self) -> &InnerFlowId { &self.state.flow } diff --git a/lib/opte/src/engine/rule.rs b/lib/opte/src/engine/rule.rs index 6e14c3bb..0b2fe198 100644 --- a/lib/opte/src/engine/rule.rs +++ b/lib/opte/src/engine/rule.rs @@ -303,45 +303,6 @@ 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, diff --git a/lib/opte/src/engine/snat.rs b/lib/opte/src/engine/snat.rs index 07adb1c8..f9459459 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.proto.into(); + 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, From cb20ed2a92a262ac29c29637746d9c9fb9348763 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Thu, 14 Mar 2024 17:36:42 +0000 Subject: [PATCH 06/18] Correctly type all InnerFlowId SDT args `uintptr_t` maybe be easy to stick in a probe, but it is also a footgun. This fixdes the display for e.g. port-process-return, but does not affect the actual panics mentioned in #476. --- crates/opte-api/src/ip.rs | 2 ++ lib/opte/src/engine/flow_table.rs | 6 +++--- lib/opte/src/engine/layer.rs | 16 ++++++++-------- lib/opte/src/engine/port.rs | 28 ++++++++++++++-------------- lib/opte/src/engine/tcp_state.rs | 8 ++++---- xde/src/xde.rs | 5 +++-- 6 files changed, 34 insertions(+), 31 deletions(-) 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/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index 85483594..1c57fa71 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -231,7 +231,7 @@ fn flow_expired_probe( __dtrace_probe_flow__expired( port.as_ptr() as uintptr_t, name.as_ptr() as uintptr_t, - flowid as *const _ 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, ); @@ -325,7 +325,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, ); @@ -334,7 +334,7 @@ extern "C" { dir: uintptr_t, port: uintptr_t, layer: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, epoch: uintptr_t, ); } diff --git a/lib/opte/src/engine/layer.rs b/lib/opte/src/engine/layer.rs index e9e55e8d..73de5df2 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -576,7 +576,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 as *const _ as uintptr_t, + flow, msg_c.as_ptr() as uintptr_t, ); } @@ -611,7 +611,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 as *const _ as uintptr_t, + flow, msg_c.as_ptr() as uintptr_t, ); } @@ -648,7 +648,7 @@ impl Layer { dir as uintptr_t, self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, - ifid as *const _ as uintptr_t, + ifid, ); } } else if #[cfg(feature = "usdt")] { @@ -1458,7 +1458,7 @@ impl Layer { self.port_c.as_ptr() as uintptr_t, self.name_c.as_ptr() as uintptr_t, dir as uintptr_t, - flow_id as *const _ as uintptr_t, + flow_id, ); } } else if #[cfg(feature = "usdt")] { @@ -1770,7 +1770,7 @@ extern "C" { port: uintptr_t, layer: uintptr_t, dir: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, msg: uintptr_t, ); @@ -1778,7 +1778,7 @@ extern "C" { port: uintptr_t, layer: uintptr_t, dir: uintptr_t, - ifid: uintptr_t, + ifid: *const InnerFlowId, msg: uintptr_t, ); @@ -1786,7 +1786,7 @@ 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, @@ -1804,7 +1804,7 @@ extern "C" { port: uintptr_t, layer: uintptr_t, dir: uintptr_t, - flow: uintptr_t, + flow: *const InnerFlowId, ); } diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 9200eb63..442b40d3 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -859,7 +859,7 @@ impl Port { __dtrace_probe_tcp__err( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - flow as *const _ as uintptr_t, + flow, mblk_addr, msg_arg.as_ptr() as uintptr_t, ); @@ -1411,7 +1411,7 @@ impl Port { __dtrace_probe_port__process__entry( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - flow as *const _ as uintptr_t, + flow, epoch as uintptr_t, pkt.mblk_addr(), ); @@ -1456,8 +1456,8 @@ impl Port { __dtrace_probe_port__process__return( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - flow_before as *const _ as uintptr_t, - &flow_after as *const _ as uintptr_t, + flow_before, + flow_after, epoch as uintptr_t, pkt.mblk_addr(), hp_pkt_ptr, @@ -1879,7 +1879,7 @@ impl Port { __dtrace_probe_uft__hit( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - ufid as *const _ as uintptr_t, + ufid, epoch as uintptr_t, last_hit.raw_millis().unwrap_or_default() as usize ); @@ -2342,7 +2342,7 @@ impl Port { __dtrace_probe_uft__invalidate( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - ufid as *const _ as uintptr_t, + ufid, epoch as uintptr_t, ); } @@ -2379,7 +2379,7 @@ impl Port { __dtrace_probe_uft__tcp__closed( dir as uintptr_t, self.name_cstr.as_ptr() as uintptr_t, - ufid as *const _ as uintptr_t, + ufid, ); } } else if #[cfg(feature = "usdt")] { @@ -2661,15 +2661,15 @@ 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, @@ -2678,27 +2678,27 @@ extern "C" { 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/tcp_state.rs b/lib/opte/src/engine/tcp_state.rs index 708b152c..62423648 100644 --- a/lib/opte/src/engine/tcp_state.rs +++ b/lib/opte/src/engine/tcp_state.rs @@ -587,7 +587,7 @@ impl TcpFlowState { unsafe { __dtrace_probe_tcp__flow__drop( port.as_ptr() as uintptr_t, - flow_id as *const _ as uintptr_t, + flow_id, &state as *const tcp_flow_state_sdt_arg as uintptr_t, dir as uintptr_t, flags as uintptr_t, @@ -623,7 +623,7 @@ impl TcpFlowState { unsafe { __dtrace_probe_tcp__flow__state( port.as_ptr() as uintptr_t, - flow_id as *const _ as uintptr_t, + flow_id, self.tcp_state as uintptr_t, new_state as uintptr_t, ); @@ -674,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/xde/src/xde.rs b/xde/src/xde.rs index 8a7b8693..4bdc32f2 100644 --- a/xde/src/xde.rs +++ b/xde/src/xde.rs @@ -33,6 +33,7 @@ use alloc::string::String; use alloc::string::ToString; use alloc::sync::Arc; use alloc::vec::Vec; +use opte::engine::packet::InnerFlowId; use core::convert::TryInto; use core::ffi::CStr; use core::num::NonZeroU32; @@ -127,7 +128,7 @@ extern "C" { ); pub fn __dtrace_probe_guest__loopback( mp: uintptr_t, - flow: uintptr_t, + flow: *const InnerFlowId, src_port: uintptr_t, dst_port: uintptr_t, ); @@ -1333,7 +1334,7 @@ fn guest_loopback_probe(pkt: &Packet, src: &XdeDev, dst: &XdeDev) { unsafe { __dtrace_probe_guest__loopback( pkt.mblk_addr(), - pkt.flow() as *const _ as uintptr_t, + pkt.flow(), src.port.name_cstr().as_ptr() as uintptr_t, dst.port.name_cstr().as_ptr() as uintptr_t, ) From 60e0b84d30938318867a3587b000a313de59d597 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Thu, 14 Mar 2024 18:00:49 +0000 Subject: [PATCH 07/18] I suppose that's technically an API change. --- crates/opte-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/opte-api/src/lib.rs b/crates/opte-api/src/lib.rs index c82d1cb2..60b1c1d7 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 = 28; +pub const API_VERSION: u64 = 29; /// Major version of the OPTE package. pub const MAJOR_VERSION: u64 = 0; From 1c37083ee119fd5c3a60825f846cdce8123f7069 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 15 Mar 2024 14:04:34 +0000 Subject: [PATCH 08/18] A hopefully temporary workaround for opte#476. It appears that JMP'd dtrace probes are being rewritten at load time without a RTN. Near as I can tell, rustc offers no way to say 'don't tail-call optimise this thing', so I'm forcing in a ZST with a drop impl to achieve similar behaviour. Hopefully this suffices. --- lib/opte/src/engine/flow_table.rs | 18 ++++++++++-------- lib/opte/src/engine/layer.rs | 2 -- lib/opte/src/engine/port.rs | 12 ++++++++++-- lib/opte/src/lib.rs | 14 ++++++++++++++ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index 1c57fa71..c60e6e62 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -127,7 +127,7 @@ where } pub fn expire(&mut self, flowid: &InnerFlowId) { - // flow_expired_probe(&self.port_c, &self.name_c, flowid, None, None); + flow_expired_probe(&self.port_c, &self.name_c, flowid, None, None); self.map.remove(flowid); } @@ -141,13 +141,13 @@ where self.map.retain(|flowid, entry| { if self.policy.is_expired(entry, now) { - // flow_expired_probe( - // port_c, - // name_c, - // flowid, - // Some(entry.last_hit), - // Some(now), - // ); + flow_expired_probe( + port_c, + name_c, + flowid, + Some(entry.last_hit), + Some(now), + ); expired.push(f(entry.state())); return false; } @@ -224,6 +224,7 @@ fn flow_expired_probe( last_hit: Option, now: Option, ) { + let a = crate::NopDrop; last_hit.unwrap_or_default(); cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { @@ -247,6 +248,7 @@ fn flow_expired_probe( let (_, _, _) = (port, name, flowid); } } + drop(a); } /// A type that can be "dumped" for the purposes of presenting an diff --git a/lib/opte/src/engine/layer.rs b/lib/opte/src/engine/layer.rs index 73de5df2..71e01d61 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -671,8 +671,6 @@ impl Layer { flow_after: &InnerFlowId, res: &result::Result, ) { - // opte::engine::err!("are we stable tables? {:p}", flow_after); - // opte::engine::err!("are we stabler tables? {:?}", flow_after); cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { // XXX This would probably be better as separate probes; diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 442b40d3..97eb7cad 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -2336,6 +2336,8 @@ impl Port { ufid: &InnerFlowId, epoch: u64, ) { + let a = crate::NopDrop; + cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { unsafe { @@ -2356,6 +2358,8 @@ impl Port { let (_, _, _) = (dir, ufid, epoch); } } + + drop(a); } fn uft_tcp_closed( @@ -2366,13 +2370,15 @@ impl Port { ) { if let Some(ufid_in) = ufid_in { data.uft_in.remove(ufid_in); - // self.uft_tcp_closed_probe(Direction::In, ufid_in); + self.uft_tcp_closed_probe(Direction::In, ufid_in); } data.uft_out.remove(ufid_out); - // self.uft_tcp_closed_probe(Direction::Out, ufid_out); + self.uft_tcp_closed_probe(Direction::Out, ufid_out); } fn uft_tcp_closed_probe(&self, dir: Direction, ufid: &InnerFlowId) { + let a = crate::NopDrop; + cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { unsafe { @@ -2392,6 +2398,8 @@ impl Port { let (_, _) = (dir, ufid); } } + + drop(a); } fn update_stats_in( diff --git a/lib/opte/src/lib.rs b/lib/opte/src/lib.rs index 970e02ee..a59629f5 100644 --- a/lib/opte/src/lib.rs +++ b/lib/opte/src/lib.rs @@ -170,6 +170,20 @@ mod opte_provider { } } +/// A *temporary* sledgehammer used to prevent tail-call optimisation +/// from being applied to SDTs. This forces a destructor to be fired +/// at the epilogue of a function, stopping LLVM from inserting a JMP +/// to a DTrace SDT probe (which are fixed up incorrectly, without a RET). +/// +/// See: opte#476. +pub struct NopDrop; + +impl Drop for NopDrop { + fn drop(&mut self) { + core::hint::black_box(self); + } +} + // ================================================================ // Providers // From baed8d0d671afba6d7f07ce412224f82eabe70af Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 15 Mar 2024 15:17:42 +0000 Subject: [PATCH 09/18] Unformat (most of) the Ok cases for packet probes --- lib/opte/src/engine/layer.rs | 44 +++++++++++++++++++++++++++++------- lib/opte/src/engine/port.rs | 44 +++++++++++++++++++++++++++++------- xde/src/xde.rs | 8 +++---- 3 files changed, 76 insertions(+), 20 deletions(-) diff --git a/lib/opte/src/engine/layer.rs b/lib/opte/src/engine/layer.rs index 71e01d61..f449f4f3 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -32,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::ErrorBlock; use crate::ddi::kstat; use crate::ddi::kstat::KStatNamed; use crate::ddi::kstat::KStatProvider; @@ -116,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, } @@ -675,22 +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 }) => ( + ErrorBlock::from_err(v), + Some(format!("{name}, {reason:?}\0")) + ), + Ok(v) => (ErrorBlock::from_err(v), None), + // TODO: Handle the error types in a zero-cost way. + Err(e) => (Ok(ErrorBlock::new()), Some(format!("ERROR: {:?}\0", e))), }; - let res_c = CString::new(res_str).unwrap(); + + // Truncation is captured *in* the ErrorBlock. + 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_before, flow_after, - res_c.as_ptr() as uintptr_t, + 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(); @@ -1792,7 +1820,7 @@ extern "C" { name: uintptr_t, flow_before: *const InnerFlowId, flow_after: *const InnerFlowId, - res: uintptr_t, + res: *const ErrorBlock<2>, ); pub fn __dtrace_probe_rule__match(arg: uintptr_t); diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 97eb7cad..12d02f16 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -41,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::ErrorBlock; use crate::ddi::kstat; use crate::ddi::kstat::KStatNamed; use crate::ddi::kstat::KStatProvider; @@ -125,11 +128,14 @@ 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 }, + Drop { + reason: DropReason, + }, Modified, + #[leaf] Hairpin(Packet), } @@ -1436,15 +1442,33 @@ impl Port { res: &result::Result, ) { let flow_after = pkt.flow(); + cfg_if! { 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 @ ProcessResult::Drop { reason }) => ( + ErrorBlock::from_err(v), + Some(format!("{reason:?}\0")) + ), + Ok(v) => (ErrorBlock::from_err(v), None), + // TODO: Handle the error types in a zero-cost way. + Err(e) => (Ok(ErrorBlock::new()), Some(format!("ERROR: {:?}\0", e))), }; - let res_arg = CString::new(res_str).unwrap(); + + // Truncation is captured *in* the ErrorBlock. + 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() @@ -1453,6 +1477,9 @@ 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, @@ -1461,10 +1488,11 @@ impl Port { epoch as uintptr_t, pkt.mblk_addr(), hp_pkt_ptr, - res_arg.as_ptr() as uintptr_t, + eb.as_ptr(), ); } + drop(extra_str); } else if #[cfg(feature = "usdt")] { let flow_b_s = flow_before.to_string(); let flow_a_s = flow_after.to_string(); @@ -2681,7 +2709,7 @@ extern "C" { epoch: uintptr_t, pkt: uintptr_t, hp_pkt: uintptr_t, - res: uintptr_t, + err_b: *const ErrorBlock<2>, ); pub fn __dtrace_probe_tcp__err( dir: uintptr_t, diff --git a/xde/src/xde.rs b/xde/src/xde.rs index 4bdc32f2..00c3ab95 100644 --- a/xde/src/xde.rs +++ b/xde/src/xde.rs @@ -33,7 +33,6 @@ use alloc::string::String; use alloc::string::ToString; use alloc::sync::Arc; use alloc::vec::Vec; -use opte::engine::packet::InnerFlowId; use core::convert::TryInto; use core::ffi::CStr; use core::num::NonZeroU32; @@ -62,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; @@ -123,7 +123,7 @@ extern "C" { port: uintptr_t, dir: uintptr_t, mp: uintptr_t, - err_b: uintptr_t, + err_b: *const ErrorBlock<8>, data_len: uintptr_t, ); pub fn __dtrace_probe_guest__loopback( @@ -167,7 +167,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, ) }; @@ -191,7 +191,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, ) }; From 4e2ad7eeb9fa653688ea5290d3175213a35d26ac Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 15 Mar 2024 19:25:09 +0000 Subject: [PATCH 10/18] Fixup dtrace scripts, nicer format on drop --- dtrace/common.h | 3 +++ dtrace/opte-bad-packet.d | 33 +++++++++++++++++++++------------ dtrace/opte-layer-process.d | 17 ++++++++++++++++- dtrace/opte-port-process.d | 18 ++++++++++++++++-- lib/opte/src/engine/layer.rs | 2 +- lib/opte/src/engine/port.rs | 1 + 6 files changed, 58 insertions(+), 16 deletions(-) diff --git a/dtrace/common.h b/dtrace/common.h index c412b405..9e286d86 100644 --- a/dtrace/common.h +++ b/dtrace/common.h @@ -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/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/engine/layer.rs b/lib/opte/src/engine/layer.rs index f449f4f3..12205263 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -686,7 +686,7 @@ impl Layer { let (eb, extra_str) = match res { Ok(v @ LayerResult::Deny { name, reason }) => ( ErrorBlock::from_err(v), - Some(format!("{name}, {reason:?}\0")) + Some(format!("{{name: \"{name}\", reason: {reason:?}}}\0")) ), Ok(v) => (ErrorBlock::from_err(v), None), // TODO: Handle the error types in a zero-cost way. diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 12d02f16..fb6616cc 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -131,6 +131,7 @@ impl From for ProcessError { #[derive(Debug, DError)] pub enum ProcessResult { Bypass, + #[leaf] Drop { reason: DropReason, }, From 74bed9879b119a4f1b5a62195776116f757bceae Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Thu, 25 Apr 2024 12:28:14 +0100 Subject: [PATCH 11/18] Minor nit caught on self-review. --- lib/opte/src/engine/packet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/opte/src/engine/packet.rs b/lib/opte/src/engine/packet.rs index 0260e7d3..ca55b8f6 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -1470,7 +1470,7 @@ impl Packet { } /// Return a reference to the flow ID of this packet. - // #[inline] + #[inline] pub fn flow(&self) -> &InnerFlowId { &self.state.flow } From a2cab3bbb2749dedd68c0deee391acac38e379c3 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 26 Apr 2024 11:29:50 +0100 Subject: [PATCH 12/18] Review feedback: Matt (hidden tail-call prevention) --- dtrace/lib/common.d | 2 +- lib/opte/src/engine/port.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dtrace/lib/common.d b/dtrace/lib/common.d index 83c519bd..21e36a67 100644 --- a/dtrace/lib/common.d +++ b/dtrace/lib/common.d @@ -3,7 +3,7 @@ typedef struct flow_id_sdt_arg { uint8_t proto; - uint16_t af; + uint16_t af; union addrs { ipaddr_t ip4[2]; in6_addr_t ip6[2]; diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index fb6616cc..e442eaef 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. @@ -1444,8 +1444,11 @@ impl Port { ) { let flow_after = pkt.flow(); + let a = crate::NopDrop; + cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { + // XXX This would probably be better as separate probes; // for now this does the trick. let (eb, extra_str) = match res { @@ -1492,8 +1495,6 @@ impl Port { eb.as_ptr(), ); } - - drop(extra_str); } else if #[cfg(feature = "usdt")] { let flow_b_s = flow_before.to_string(); let flow_a_s = flow_after.to_string(); @@ -1515,6 +1516,8 @@ impl Port { let (..) = (dir, flow_before, flow_after, epoch, pkt, res); } } + + drop(a); } /// Creates a new TCP flow state entry for a given packet. From 1e7506e1b5bc14491ba39fd458d60a5ccc2264c9 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 26 Apr 2024 11:30:50 +0100 Subject: [PATCH 13/18] Re-bump API version. --- crates/opte-api/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; From fffbabade9fce169feff8498d4c7cba1de94ee43 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 26 Apr 2024 12:04:01 +0100 Subject: [PATCH 14/18] Review Feedback: Luqman pt.1 --- dtrace/common.h | 12 ++++++------ dtrace/lib/common.d | 10 ++++++++-- lib/opte/src/engine/packet.rs | 13 ++++++++----- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/dtrace/common.h b/dtrace/common.h index 9e286d86..bb642d03 100644 --- a/dtrace/common.h +++ b/dtrace/common.h @@ -9,13 +9,13 @@ #define FLOW_FMT(svar, fvar) \ this->src_ip = (ipaddr_t *)alloca(4); \ this->dst_ip = (ipaddr_t *)alloca(4); \ - *this->src_ip = fvar->addrs.ip4[0]; \ - *this->dst_ip = fvar->addrs.ip4[1]; \ + *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(fvar->src_port)); \ + svar = strjoin(svar, lltostr(fvar->src_port)); \ svar = strjoin(svar, ","); \ svar = strjoin(svar, inet_ntoa(this->dst_ip)); \ svar = strjoin(svar, ":"); \ @@ -24,13 +24,13 @@ #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->addrs.ip6[0]; \ - *this->dst_ip6 = fvar->addrs.ip6[1]; \ + *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(fvar->src_port)); \ + svar = strjoin(svar, lltostr(fvar->src_port)); \ svar = strjoin(svar, ",["); \ svar = strjoin(svar, inet_ntoa6(this->dst_ip6)); \ svar = strjoin(svar, "]:"); \ diff --git a/dtrace/lib/common.d b/dtrace/lib/common.d index 21e36a67..bdf41bfa 100644 --- a/dtrace/lib/common.d +++ b/dtrace/lib/common.d @@ -5,8 +5,14 @@ typedef struct flow_id_sdt_arg { uint8_t proto; uint16_t af; union addrs { - ipaddr_t ip4[2]; - in6_addr_t ip6[2]; + 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; diff --git a/lib/opte/src/engine/packet.rs b/lib/opte/src/engine/packet.rs index ca55b8f6..e1d6d61c 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -114,11 +114,14 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { )] #[repr(C)] pub struct InnerFlowId { - // Using a `u8` here for `proto` hides the enum repr from SDTs, - // but we need to have a `u16` discriminant for the IPs to set up - // 4B alignment on inaddr6_t on the dtrace side (so we lose out - // on the possibility of 38B packing). + // 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. pub addrs: AddrPair, pub src_port: u16, pub dst_port: u16, @@ -142,7 +145,7 @@ impl Default for InnerFlowId { PartialOrd, Serialize, )] -#[repr(u16)] +#[repr(C, u16)] pub enum AddrPair { V4 { src: Ipv4Addr, dst: Ipv4Addr } = AF_INET as u16, V6 { src: Ipv6Addr, dst: Ipv6Addr } = AF_INET6 as u16, From 0bf91e62970b322651a7fd740c7a9abb58831768 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 26 Apr 2024 14:43:10 +0100 Subject: [PATCH 15/18] InnerFlowId needs 4B alignment itself. Realised when I was out that this struct only has 2B alignment, so there was a possibility of passing up an unaligned reference to an SDT. --- dtrace/lib/common.d | 22 +++++++++++----------- lib/opte/src/engine/packet.rs | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dtrace/lib/common.d b/dtrace/lib/common.d index bdf41bfa..e4fe26d0 100644 --- a/dtrace/lib/common.d +++ b/dtrace/lib/common.d @@ -6,13 +6,13 @@ typedef struct flow_id_sdt_arg { uint16_t af; union addrs { struct { - ipaddr_t src; - ipaddr_t dst; - } ip4; - struct { - in6_addr_t src; - in6_addr_t dst; - } ip6; + 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; @@ -54,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/lib/opte/src/engine/packet.rs b/lib/opte/src/engine/packet.rs index e1d6d61c..2942659f 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -112,7 +112,7 @@ pub static FLOW_ID_DEFAULT: InnerFlowId = InnerFlowId { PartialOrd, Serialize, )] -#[repr(C)] +#[repr(C, align(4))] pub struct InnerFlowId { // Using a `u8` here for `proto` hides the enum repr from SDTs. pub proto: u8, @@ -121,7 +121,7 @@ pub struct InnerFlowId { // 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. + // enum variant data (and this struct itself is 4B aligned). pub addrs: AddrPair, pub src_port: u16, pub dst_port: u16, From ddc1b98ace02282b9f387cefa7e361eba2007ec2 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 26 Apr 2024 14:59:21 +0100 Subject: [PATCH 16/18] Review Feedback: Luqman pt.2 --- lib/opte/src/engine/packet.rs | 6 +++++- lib/opte/src/engine/print.rs | 18 ++++++------------ lib/opte/src/engine/snat.rs | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/lib/opte/src/engine/packet.rs b/lib/opte/src/engine/packet.rs index 2942659f..098acbd1 100644 --- a/lib/opte/src/engine/packet.rs +++ b/lib/opte/src/engine/packet.rs @@ -185,6 +185,10 @@ impl InnerFlowId { AddrPair::V6 { dst, .. } => dst.into(), } } + + pub fn protocol(&self) -> Protocol { + Protocol::from(self.proto) + } } impl Display for InnerFlowId { @@ -192,7 +196,7 @@ impl Display for InnerFlowId { write!( f, "{}:{}:{}:{}:{}", - self.proto, + self.protocol(), self.src_ip(), self.src_port, self.dst_ip(), diff --git a/lib/opte/src/engine/print.rs b/lib/opte/src/engine/print.rs index ce08061c..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/snat.rs b/lib/opte/src/engine/snat.rs index f9459459..39b2ed85 100644 --- a/lib/opte/src/engine/snat.rs +++ b/lib/opte/src/engine/snat.rs @@ -306,7 +306,7 @@ where _meta: &mut ActionMeta, ) -> GenDescResult { let priv_port = flow_id.src_port; - let proto = flow_id.proto.into(); + let proto = flow_id.protocol(); let is_icmp = proto == T::MESSAGE_PROTOCOL; let pool = match proto { Protocol::TCP => &self.tcp_pool, From 0edd7e6ed61f96afc40ef8525ee33910758f0bd9 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 26 Apr 2024 15:16:24 +0100 Subject: [PATCH 17/18] Friendlier names -- `LabelBlock`, `::from_nested` Given that we're now using these to handle nested `Ok(...)` types rather than just error variants, a rename was a bit in order. `DError` might also benefit? --- lib/opte/src/d_error.rs | 58 +++++++++++++++++++----------------- lib/opte/src/engine/layer.rs | 12 ++++---- lib/opte/src/engine/port.rs | 12 ++++---- xde/src/xde.rs | 10 +++---- 4 files changed, 47 insertions(+), 45 deletions(-) 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/layer.rs b/lib/opte/src/engine/layer.rs index 12205263..bfdb053c 100644 --- a/lib/opte/src/engine/layer.rs +++ b/lib/opte/src/engine/layer.rs @@ -34,7 +34,7 @@ use super::rule::HdrTransformError; use super::rule::Rule; use crate::d_error::DError; #[cfg(all(not(feature = "std"), not(test)))] -use crate::d_error::ErrorBlock; +use crate::d_error::LabelBlock; use crate::ddi::kstat; use crate::ddi::kstat::KStatNamed; use crate::ddi::kstat::KStatProvider; @@ -685,15 +685,15 @@ impl Layer { // for now this does the trick. let (eb, extra_str) = match res { Ok(v @ LayerResult::Deny { name, reason }) => ( - ErrorBlock::from_err(v), + LabelBlock::from_nested(v), Some(format!("{{name: \"{name}\", reason: {reason:?}}}\0")) ), - Ok(v) => (ErrorBlock::from_err(v), None), + Ok(v) => (LabelBlock::from_nested(v), None), // TODO: Handle the error types in a zero-cost way. - Err(e) => (Ok(ErrorBlock::new()), Some(format!("ERROR: {:?}\0", e))), + Err(e) => (Ok(LabelBlock::new()), Some(format!("ERROR: {:?}\0", e))), }; - // Truncation is captured *in* the ErrorBlock. + // Truncation is captured *in* the LabelBlock. let mut eb = match eb { Ok(block) => block, Err(block) => block, @@ -1820,7 +1820,7 @@ extern "C" { name: uintptr_t, flow_before: *const InnerFlowId, flow_after: *const InnerFlowId, - res: *const ErrorBlock<2>, + res: *const LabelBlock<2>, ); pub fn __dtrace_probe_rule__match(arg: uintptr_t); diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index 615e5c43..c84ea20f 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -43,7 +43,7 @@ use super::HdlPktAction; use super::NetworkImpl; use crate::d_error::DError; #[cfg(all(not(feature = "std"), not(test)))] -use crate::d_error::ErrorBlock; +use crate::d_error::LabelBlock; use crate::ddi::kstat; use crate::ddi::kstat::KStatNamed; use crate::ddi::kstat::KStatProvider; @@ -1459,15 +1459,15 @@ impl Port { // for now this does the trick. let (eb, extra_str) = match res { Ok(v @ ProcessResult::Drop { reason }) => ( - ErrorBlock::from_err(v), + LabelBlock::from_nested(v), Some(format!("{reason:?}\0")) ), - Ok(v) => (ErrorBlock::from_err(v), None), + Ok(v) => (LabelBlock::from_nested(v), None), // TODO: Handle the error types in a zero-cost way. - Err(e) => (Ok(ErrorBlock::new()), Some(format!("ERROR: {:?}\0", e))), + Err(e) => (Ok(LabelBlock::new()), Some(format!("ERROR: {:?}\0", e))), }; - // Truncation is captured *in* the ErrorBlock. + // Truncation is captured *in* the LabelBlock. let mut eb = match eb { Ok(block) => block, Err(block) => block, @@ -2688,7 +2688,7 @@ extern "C" { epoch: uintptr_t, pkt: uintptr_t, hp_pkt: uintptr_t, - err_b: *const ErrorBlock<2>, + err_b: *const LabelBlock<2>, ); pub fn __dtrace_probe_tcp__err( dir: uintptr_t, diff --git a/xde/src/xde.rs b/xde/src/xde.rs index eab90070..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; @@ -128,7 +128,7 @@ extern "C" { port: uintptr_t, dir: uintptr_t, mp: uintptr_t, - err_b: *const ErrorBlock<8>, + err_b: *const LabelBlock<8>, data_len: uintptr_t, ); pub fn __dtrace_probe_guest__loopback( @@ -161,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, }; @@ -188,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); From 8237f425f450c295f997fc69a5913a328b1900e2 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Fri, 10 May 2024 12:39:01 +0100 Subject: [PATCH 18/18] Remove `NopDrop` and its uses --- lib/opte/src/engine/flow_table.rs | 3 --- lib/opte/src/engine/port.rs | 12 ------------ lib/opte/src/lib.rs | 14 -------------- 3 files changed, 29 deletions(-) diff --git a/lib/opte/src/engine/flow_table.rs b/lib/opte/src/engine/flow_table.rs index c60e6e62..4bd53d27 100644 --- a/lib/opte/src/engine/flow_table.rs +++ b/lib/opte/src/engine/flow_table.rs @@ -224,8 +224,6 @@ fn flow_expired_probe( last_hit: Option, now: Option, ) { - let a = crate::NopDrop; - last_hit.unwrap_or_default(); cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { unsafe { @@ -248,7 +246,6 @@ fn flow_expired_probe( let (_, _, _) = (port, name, flowid); } } - drop(a); } /// A type that can be "dumped" for the purposes of presenting an diff --git a/lib/opte/src/engine/port.rs b/lib/opte/src/engine/port.rs index c84ea20f..ad6d215d 100644 --- a/lib/opte/src/engine/port.rs +++ b/lib/opte/src/engine/port.rs @@ -1450,8 +1450,6 @@ impl Port { ) { let flow_after = pkt.flow(); - let a = crate::NopDrop; - cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { @@ -1522,8 +1520,6 @@ impl Port { let (..) = (dir, flow_before, flow_after, epoch, pkt, res); } } - - drop(a); } /// Creates a new TCP flow state entry for a given packet. @@ -2343,8 +2339,6 @@ impl Port { ufid: &InnerFlowId, epoch: u64, ) { - let a = crate::NopDrop; - cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { unsafe { @@ -2365,8 +2359,6 @@ impl Port { let (_, _, _) = (dir, ufid, epoch); } } - - drop(a); } fn uft_tcp_closed( @@ -2384,8 +2376,6 @@ impl Port { } fn uft_tcp_closed_probe(&self, dir: Direction, ufid: &InnerFlowId) { - let a = crate::NopDrop; - cfg_if::cfg_if! { if #[cfg(all(not(feature = "std"), not(test)))] { unsafe { @@ -2405,8 +2395,6 @@ impl Port { let (_, _) = (dir, ufid); } } - - drop(a); } fn update_stats_in( diff --git a/lib/opte/src/lib.rs b/lib/opte/src/lib.rs index a59629f5..970e02ee 100644 --- a/lib/opte/src/lib.rs +++ b/lib/opte/src/lib.rs @@ -170,20 +170,6 @@ mod opte_provider { } } -/// A *temporary* sledgehammer used to prevent tail-call optimisation -/// from being applied to SDTs. This forces a destructor to be fired -/// at the epilogue of a function, stopping LLVM from inserting a JMP -/// to a DTrace SDT probe (which are fixed up incorrectly, without a RET). -/// -/// See: opte#476. -pub struct NopDrop; - -impl Drop for NopDrop { - fn drop(&mut self) { - core::hint::black_box(self); - } -} - // ================================================================ // Providers //