Skip to content

Commit 566cf6d

Browse files
author
Artem Kryvokrysenko
committed
tracer: update public API for smoltcp::phy::Tracer to allow custom inspection and printing of packet
Currently `smoltcp::phy::tracer::Packet` is not exported as public type, which leaves very limited options for using `Tracer` device: traced packets only can be directly printed "as-is" and only in limited context (inside the closure). I'm updating API of `Tracer` device to provide access to internal fields of traced packet; this will enable implementation of custom printing or packet inspection functions I renamed `smoltcp::phy::tracer::Packet` to `smoltcp::phy::tracer::TracerPacket`, following prefixing convention used by types declared in `smoltcp::phy::pcap_writer`
1 parent a54589c commit 566cf6d

File tree

2 files changed

+167
-16
lines changed

2 files changed

+167
-16
lines changed

src/phy/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub use self::loopback::Loopback;
125125
pub use self::pcap_writer::{PcapLinkType, PcapMode, PcapSink, PcapWriter};
126126
#[cfg(all(feature = "phy-raw_socket", unix))]
127127
pub use self::raw_socket::RawSocket;
128-
pub use self::tracer::Tracer;
128+
pub use self::tracer::{Tracer, TracerDirection, TracerPacket};
129129
#[cfg(all(
130130
feature = "phy-tuntap_interface",
131131
any(target_os = "linux", target_os = "android")

src/phy/tracer.rs

Lines changed: 166 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@ use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
1111
/// device.
1212
pub struct Tracer<D: Device> {
1313
inner: D,
14-
writer: fn(Instant, Packet),
14+
writer: fn(Instant, TracerPacket),
1515
}
1616

1717
impl<D: Device> Tracer<D> {
18-
/// Create a tracer device.
19-
pub fn new(inner: D, writer: fn(timestamp: Instant, packet: Packet)) -> Tracer<D> {
18+
pub fn new(inner: D, writer: fn(timestamp: Instant, packet: TracerPacket)) -> Tracer<D> {
2019
Tracer { inner, writer }
2120
}
2221

@@ -88,7 +87,7 @@ impl<D: Device> Device for Tracer<D> {
8887
#[doc(hidden)]
8988
pub struct RxToken<Rx: phy::RxToken> {
9089
token: Rx,
91-
writer: fn(Instant, Packet),
90+
writer: fn(Instant, TracerPacket),
9291
medium: Medium,
9392
timestamp: Instant,
9493
}
@@ -101,10 +100,10 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
101100
self.token.consume(|buffer| {
102101
(self.writer)(
103102
self.timestamp,
104-
Packet {
103+
TracerPacket {
105104
buffer,
106105
medium: self.medium,
107-
prefix: "<- ",
106+
direction: TracerDirection::RX,
108107
},
109108
);
110109
f(buffer)
@@ -119,7 +118,7 @@ impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
119118
#[doc(hidden)]
120119
pub struct TxToken<Tx: phy::TxToken> {
121120
token: Tx,
122-
writer: fn(Instant, Packet),
121+
writer: fn(Instant, TracerPacket),
123122
medium: Medium,
124123
timestamp: Instant,
125124
}
@@ -133,10 +132,10 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
133132
let result = f(buffer);
134133
(self.writer)(
135134
self.timestamp,
136-
Packet {
135+
TracerPacket {
137136
buffer,
138137
medium: self.medium,
139-
prefix: "-> ",
138+
direction: TracerDirection::TX,
140139
},
141140
);
142141
result
@@ -148,15 +147,34 @@ impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
148147
}
149148
}
150149

151-
pub struct Packet<'a> {
152-
buffer: &'a [u8],
153-
medium: Medium,
154-
prefix: &'static str,
150+
/// Packet which is being traced by [Tracer](struct.Tracer.html) device.
151+
#[derive(Debug, Clone, Copy)]
152+
pub struct TracerPacket<'a> {
153+
/// Packet buffer
154+
pub buffer: &'a [u8],
155+
/// Packet medium
156+
pub medium: Medium,
157+
/// Direction in which packet is being traced
158+
pub direction: TracerDirection,
159+
}
160+
161+
/// Direction on which packet is being traced
162+
#[derive(Debug, Clone, Copy, PartialEq)]
163+
pub enum TracerDirection {
164+
/// Packet is received by Smoltcp interface
165+
RX,
166+
/// Packet is transmitted by Smoltcp interface
167+
TX,
155168
}
156169

157-
impl<'a> fmt::Display for Packet<'a> {
170+
impl<'a> fmt::Display for TracerPacket<'a> {
158171
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159-
let mut indent = PrettyIndent::new(self.prefix);
172+
let prefix = match self.direction {
173+
TracerDirection::RX => "<- ",
174+
TracerDirection::TX => "-> ",
175+
};
176+
177+
let mut indent = PrettyIndent::new(prefix);
160178
match self.medium {
161179
#[cfg(feature = "medium-ethernet")]
162180
Medium::Ethernet => crate::wire::EthernetFrame::<&'static [u8]>::pretty_print(
@@ -189,3 +207,136 @@ impl<'a> fmt::Display for Packet<'a> {
189207
}
190208
}
191209
}
210+
211+
#[cfg(test)]
212+
mod tests {
213+
use core::cell::RefCell;
214+
use std::collections::VecDeque;
215+
216+
use super::*;
217+
218+
use crate::phy::ChecksumCapabilities;
219+
use crate::wire::Ipv4Address;
220+
use crate::{
221+
phy::{Device, Loopback, RxToken, TxToken},
222+
time::Instant,
223+
wire::{
224+
EthernetAddress, EthernetFrame, EthernetProtocol, EthernetRepr, IpProtocol, Ipv4Packet,
225+
Ipv4Repr,
226+
},
227+
};
228+
229+
#[test]
230+
fn test_tracer() {
231+
type TracerEvent = (Instant, Vec<u8>, Medium, TracerDirection);
232+
thread_local! {
233+
static TRACE_EVENTS: RefCell<VecDeque<TracerEvent>> = const { RefCell::new(VecDeque::new()) };
234+
}
235+
TRACE_EVENTS.replace(VecDeque::new());
236+
237+
let loopback_device = Loopback::new(crate::phy::Medium::Ip);
238+
let mut tracer_device = Tracer::new(loopback_device, |instant, packet| {
239+
TRACE_EVENTS.with_borrow_mut(|events| {
240+
events.push_back((
241+
instant,
242+
packet.buffer.to_owned(),
243+
packet.medium,
244+
packet.direction,
245+
))
246+
});
247+
});
248+
249+
let expected_payload = [1, 2, 3, 4, 5, 6, 7, 8];
250+
251+
let tx_instant = Instant::from_secs(1);
252+
let tx_token = tracer_device.transmit(tx_instant).unwrap();
253+
254+
tx_token.consume(expected_payload.len(), |buf| {
255+
buf.copy_from_slice(&expected_payload)
256+
});
257+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
258+
assert_eq!(
259+
last_event,
260+
Some((
261+
tx_instant,
262+
expected_payload.into(),
263+
Medium::Ip,
264+
TracerDirection::TX
265+
))
266+
);
267+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
268+
assert_eq!(last_event, None);
269+
270+
let rx_instant = Instant::from_secs(2);
271+
let (rx_token, _) = tracer_device.receive(rx_instant).unwrap();
272+
let mut rx_pkt = [0; 8];
273+
rx_token.consume(|buf| rx_pkt.copy_from_slice(buf));
274+
275+
assert_eq!(rx_pkt, expected_payload);
276+
277+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
278+
assert_eq!(
279+
last_event,
280+
Some((
281+
rx_instant,
282+
expected_payload.into(),
283+
Medium::Ip,
284+
TracerDirection::RX
285+
))
286+
);
287+
let last_event = TRACE_EVENTS.with_borrow_mut(|events| events.pop_front());
288+
assert_eq!(last_event, None);
289+
}
290+
291+
#[test]
292+
fn test_tracer_packet_display_ether() {
293+
let repr = EthernetRepr {
294+
src_addr: EthernetAddress([0, 1, 2, 3, 4, 5]),
295+
dst_addr: EthernetAddress([5, 4, 3, 2, 1, 0]),
296+
ethertype: EthernetProtocol::Unknown(0),
297+
};
298+
let mut buffer = vec![0_u8; repr.buffer_len()];
299+
{
300+
let mut frame = EthernetFrame::new_unchecked(&mut buffer);
301+
repr.emit(&mut frame);
302+
}
303+
304+
let pkt = TracerPacket {
305+
buffer: &buffer,
306+
medium: Medium::Ethernet,
307+
direction: TracerDirection::RX,
308+
};
309+
310+
let pkt_pretty = pkt.to_string();
311+
assert_eq!(
312+
pkt_pretty,
313+
"<- EthernetII src=00-01-02-03-04-05 dst=05-04-03-02-01-00 type=0x0000"
314+
);
315+
}
316+
317+
#[test]
318+
fn test_tracer_packet_display_ip() {
319+
let repr = Ipv4Repr {
320+
src_addr: Ipv4Address::new(10, 0, 0, 1),
321+
dst_addr: Ipv4Address::new(10, 0, 0, 2),
322+
next_header: IpProtocol::Unknown(255),
323+
payload_len: 0,
324+
hop_limit: 64,
325+
};
326+
327+
let mut buffer = vec![0_u8; repr.buffer_len()];
328+
{
329+
let mut packet = Ipv4Packet::new_unchecked(&mut buffer);
330+
repr.emit(&mut packet, &ChecksumCapabilities::default());
331+
}
332+
333+
let pkt = TracerPacket {
334+
buffer: &buffer,
335+
medium: Medium::Ip,
336+
direction: TracerDirection::TX,
337+
};
338+
339+
let pkt_pretty = pkt.to_string();
340+
assert_eq!(pkt_pretty, "-> IPv4 src=10.0.0.1 dst=10.0.0.2 proto=0xff");
341+
}
342+
}

0 commit comments

Comments
 (0)