Skip to content

Commit 8139a69

Browse files
committed
MGS: Add usdt probes for receiving messages
1 parent 92e5a5c commit 8139a69

File tree

8 files changed

+118
-4
lines changed

8 files changed

+118
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gateway-sp-comms/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ futures = "0.3.21"
99
ringbuffer = "0.8"
1010
serde = { version = "1.0", features = ["derive"] }
1111
thiserror = "1.0.30"
12+
usdt = "0.3.1"
1213
uuid = "0.8"
1314

1415
gateway-messages = { path = "../gateway-messages", features = ["std"] }

gateway-sp-comms/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# `gateway-sp-comms`
2+
3+
Communicate with SPs across the management network.
4+
5+
## DTrace Probes
6+
7+
This crate currently provides three DTrace probes: receiving raw packets,
8+
receiving responses to requests, receiving serial console messages.
9+
10+
Raw packets:
11+
12+
```
13+
% sudo dtrace -n 'gateway_sp_comms*:::recv_packet { printf("%s, %s", copyinstr(arg0), copyinstr(arg1)); tracemem(copyin(arg2, arg3), 128, arg3); }'
14+
dtrace: description 'gateway_sp_comms*:::recv_packet ' matched 1 probe
15+
CPU ID FUNCTION:NAME
16+
6 2961 _ZN16gateway_sp_comms17management_switch9recv_task28_$u7b$$u7b$closure$u7d$$u7d$17h2bdb4a0aa5dcced5E:recv_packet {"ok":"127.0.0.1:23457"}, {"ok":1}
17+
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
18+
0: 01 00 00 00 01 73 70 33 00 00 00 00 00 00 00 00 .....sp3........
19+
10: 00 00 00 00 00 24 00 00 00 00 00 00 00 06 00 68 .....$.........h
20+
20: 65 6c 6c 6f 0a ello.
21+
```
22+
23+
Responses:
24+
25+
```
26+
% sudo dtrace -n 'gateway_sp_comms*:::recv_response { printf("%s, %u, %s", copyinstr(arg0), arg1, copyinstr(arg2)); }'
27+
dtrace: description 'gateway_sp_comms*:::recv_response ' matched 1 probe
28+
CPU ID FUNCTION:NAME
29+
5 2962 _ZN16gateway_sp_comms12recv_handler11RecvHandler15handle_response17h28a3ce4546c4e1bdE:recv_response {"ok":0}, 0, {"ok":{"Ok":{"IgnitionState":{"id":17,"flags":{"bits":3}}}}}
30+
2 2962 _ZN16gateway_sp_comms12recv_handler11RecvHandler15handle_response17h28a3ce4546c4e1bdE:recv_response {"ok":1}, 1, {"ok":{"Ok":{"SpState":{"serial_number":[0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3]}}}}
31+
```
32+
33+
Serial console messages:
34+
35+
```
36+
% sudo dtrace -n 'gateway_sp_comms*:::recv_serial_console { printf("%u, %s, %u", arg0, copyinstr(arg0), arg2); tracemem(copyin(arg3, arg4), 128, arg4); }'
37+
dtrace: description 'gateway_sp_comms*:::recv_serial_console ' matched 1 probe
38+
CPU ID FUNCTION:NAME
39+
2 2963 _ZN16gateway_sp_comms12recv_handler11RecvHandler21handle_serial_console17hba2bd6ac4422e295E:recv_serial_console 105553180037200, {"ok":1}, 42
40+
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
41+
0: 68 65 6c 6c 6f 21 0a hello!.
42+
```
43+
44+
TODO EXPAND

gateway-sp-comms/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
// Copyright 2022 Oxide Computer Company
66

7+
// Required nightly features for `usdt`
8+
#![cfg_attr(target_os = "macos", feature(asm_sym))]
9+
#![feature(asm)]
10+
711
//! This crate provides UDP-based communication across the Oxide management
812
//! switch to a collection of SPs.
913
//!
@@ -13,6 +17,8 @@ mod communicator;
1317
mod management_switch;
1418
mod recv_handler;
1519

20+
pub use usdt::register_probes;
21+
1622
pub mod error;
1723

1824
pub use communicator::Communicator;

gateway-sp-comms/src/management_switch.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ pub enum SpType {
6161
Power,
6262
}
6363

64-
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
64+
// We derive `Serialize` to be able to send `SwitchPort`s to usdt probes, but
65+
// critically we do _not_ implement `Deserialize` - the only way to construct a
66+
// `SwitchPort` should be to receive one from a `ManagementSwitch`.
67+
#[derive(
68+
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize,
69+
)]
70+
#[serde(transparent)]
6571
pub(crate) struct SwitchPort(usize);
6672

6773
impl SwitchPort {
@@ -365,6 +371,13 @@ where
365371

366372
match sock.try_recv_from(&mut buf) {
367373
Ok((n, addr)) => {
374+
let buf = &buf[..n];
375+
probes::recv_packet!(|| (
376+
&addr,
377+
&port,
378+
buf.as_ptr() as usize as u64,
379+
buf.len() as u64
380+
));
368381
if Some(addr) != inner.sp_socket(port).map(|s| s.addr) {
369382
// TODO what do we do here? we received a packet from an
370383
// address that doesn't match what we believe is the SP's
@@ -377,7 +390,7 @@ where
377390
);
378391
} else {
379392
debug!(inner.log, "received {} bytes", n; "port" => ?port);
380-
callback(port, &buf[..n]);
393+
callback(port, buf);
381394
}
382395
}
383396
// spurious wakeup; no need to log, just continue
@@ -590,3 +603,14 @@ mod tests {
590603
}
591604
}
592605
}
606+
607+
#[usdt::provider(provider = "gateway_sp_comms")]
608+
mod probes {
609+
fn recv_packet(
610+
_source: &SocketAddr,
611+
_port: &SwitchPort,
612+
_data: u64, // TODO actually a `*const u8`, but that isn't allowed by usdt
613+
_len: u64,
614+
) {
615+
}
616+
}

gateway-sp-comms/src/recv_handler/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ impl RecvHandler {
166166
request_id: u32,
167167
result: Result<ResponseKind, ResponseError>,
168168
) {
169+
probes::recv_response!(|| (&port, request_id, &result));
169170
match self.sp_state(port).requests.ingest_response(&request_id, result)
170171
{
171172
ResponseIngestResult::Ok => (),
@@ -181,6 +182,13 @@ impl RecvHandler {
181182
}
182183

183184
fn handle_serial_console(&self, port: SwitchPort, packet: SerialConsole) {
185+
probes::recv_serial_console!(|| (
186+
&port,
187+
&packet.component,
188+
packet.offset,
189+
packet.data.as_ptr() as usize as u64,
190+
u64::from(packet.len)
191+
));
184192
debug!(
185193
&self.log,
186194
"received serial console data from {:?}: {:?}", port, packet
@@ -198,3 +206,22 @@ struct SingleSpState {
198206
requests: RequestResponseMap<u32, Result<ResponseKind, ResponseError>>,
199207
serial_console: Mutex<SerialConsoleHistory>,
200208
}
209+
210+
#[usdt::provider(provider = "gateway_sp_comms")]
211+
mod probes {
212+
fn recv_response(
213+
_port: &SwitchPort,
214+
_request_id: u32,
215+
_result: &Result<ResponseKind, ResponseError>,
216+
) {
217+
}
218+
219+
fn recv_serial_console(
220+
_port: &SwitchPort,
221+
_component: &SpComponent,
222+
_offset: u64,
223+
_data: u64, // TODO actually a `*const u8`, but that isn't allowed by usdt
224+
_len: u64,
225+
) {
226+
}
227+
}

gateway/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub mod http_entrypoints; // TODO pub only for testing - is this right?
1212
pub use config::Config;
1313
pub use context::ServerContext;
1414

15-
use slog::{debug, error, info, o, Logger};
15+
use slog::{debug, error, info, o, warn, Logger};
1616
use std::sync::Arc;
1717
use uuid::Uuid;
1818

@@ -45,6 +45,13 @@ impl Server {
4545
let log = log.new(o!("name" => config.id.to_string()));
4646
info!(log, "setting up gateway server");
4747

48+
match gateway_sp_comms::register_probes() {
49+
Ok(_) => debug!(log, "successfully registered DTrace USDT probes"),
50+
Err(err) => {
51+
warn!(log, "failed to register DTrace USDT probes: {}", err);
52+
}
53+
}
54+
4855
let apictx =
4956
ServerContext::new(config, &log).await.map_err(|error| {
5057
format!("initializing server context: {}", error)

sp-sim/src/gimlet.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,14 @@ impl SerialConsoleTcpTask {
224224
break;
225225
}
226226
};
227+
if n == 0 {
228+
error!(self.log, "closing serial console TCP connection (read 0 bytes)");
229+
break;
230+
}
227231
match self.send_serial_console(&buf[..n]).await {
228232
Ok(()) => (),
229233
Err(err) => {
230-
error!(self.log, "ignoring UDP send failure {}", err);
234+
error!(self.log, "ignoring UDP send ({} bytes) failure {}", n, err);
231235
continue;
232236
}
233237
}

0 commit comments

Comments
 (0)