Skip to main content

manycastr/worker/
trace_codec.rs

1pub(crate) struct TraceTag {
2    /// Sending worker id (≤10 bits, up to 1024 workers).
3    pub worker_id: u32,
4    /// Probe TTL — the hop count that triggers the reply.
5    pub ttl: u8,
6    /// Low 14 bits of the send time in milliseconds.
7    pub ts14: u16,
8}
9
10impl TraceTag {
11    /// ICMP encoded in the ICMP identifier (16 bit) and sequence number (16 bit) fields
12    /// UDP encoded in the IPv4 identifier or IPv6 flow label (16 bit) and UDP checksum (16 bit)
13    pub fn encode_split(&self) -> (u16, u16) {
14        let worker_hi = ((self.worker_id >> 8) & 0x03) as u16;
15        let worker_lo = (self.worker_id & 0xFF) as u16;
16        let id_field = (worker_hi << 14) | (self.ts14 & 0x3FFF);
17        let seq_field = ((self.ttl as u16) << 8) | worker_lo;
18        (id_field, seq_field)
19    }
20
21    /// Inverse of [`TraceTag::encode_split`].
22    pub fn decode_split(id_field: u16, seq_field: u16) -> Self {
23        let worker_hi = ((id_field >> 14) & 0x03) as u32;
24        let worker_lo = (seq_field & 0xFF) as u32;
25        TraceTag {
26            worker_id: (worker_hi << 8) | worker_lo,
27            ttl: (seq_field >> 8) as u8,
28            ts14: id_field & 0x3FFF,
29        }
30    }
31
32    /// Encoded in the 32 bit seq value for TCP
33    pub fn encode_tcp_seq(&self) -> u32 {
34        let worker10 = self.worker_id & 0x3FF;
35        (worker10 << 22) | (((self.ttl as u32) & 0xFF) << 14) | (self.ts14 as u32 & 0x3FFF)
36    }
37
38    /// Inverse of [`TraceTag::encode_tcp_seq`].
39    pub fn decode_tcp_seq(seq: u32) -> Self {
40        TraceTag {
41            worker_id: (seq >> 22) & 0x3FF,
42            ttl: ((seq >> 14) & 0xFF) as u8,
43            ts14: (seq & 0x3FFF) as u16,
44        }
45    }
46}