diff --git a/docs/METRICS.md b/docs/METRICS.md index a3eecfe5..ad65ccab 100644 --- a/docs/METRICS.md +++ b/docs/METRICS.md @@ -500,6 +500,8 @@ This sampler provides telemetry about TCP traffic and connections. * `tcp/drop` - number of packets dropped in the kernel TCP stack * `tcp/tlp` - number of Tail Loss Recovery Probes sent * `tcp/transmit/retransmit_timeout` - number of retransmit timeouts +* `tcp/receive/duplicate` - number of duplicate TCP segments received. +* `tcp/receive/out_of_order` - number of out of order TCP segments received. ## UDP diff --git a/src/samplers/tcp/bpf.c b/src/samplers/tcp/bpf.c index f5c1cf45..623d7879 100644 --- a/src/samplers/tcp/bpf.c +++ b/src/samplers/tcp/bpf.c @@ -10,6 +10,7 @@ #include #include #include +#include // stores the stats of a connection. struct sock_stats_t { @@ -34,6 +35,8 @@ BPF_ARRAY(conn_initiated, u64, 1); BPF_ARRAY(drop, u64, 1); BPF_ARRAY(tlp, u64, 1); BPF_ARRAY(rto, u64, 1); +BPF_ARRAY(duplicate, u64, 1); +BPF_ARRAY(ooo, u64, 1); // store a pointer by the pid static void store_ptr(u64 pid, u64 ptr) @@ -269,3 +272,29 @@ int trace_rto(struct pt_regs *ctx, struct sock *sk) add_value(rto.lookup(&loc), 1); return 0; } + +// Run on incoming package validation +int trace_validate_incoming(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) { + if (sk == NULL || skb == NULL) + return 0; + + struct tcp_sock *tp = tcp_sk(sk); + u32 seq = TCP_SKB_CB(skb)->seq; + + // Segment sequence before the expected one + // which means this was a duplicated segment + if ((seq - tp->rcv_nxt) < 0) { + // Increment duplicate counter + int loc = 0; + add_value(duplicate.lookup(&loc), 1); + } + + // Segment sequence after the expected one + // which means this segment was received out of order + if ((tp->rcv_nxt - seq) < 0) { + // Increment out of order counter + int loc = 0; + add_value(ooo.lookup(&loc), 1); + } + return 0; +} diff --git a/src/samplers/tcp/stat.rs b/src/samplers/tcp/stat.rs index 83c07851..9e0208c3 100644 --- a/src/samplers/tcp/stat.rs +++ b/src/samplers/tcp/stat.rs @@ -88,6 +88,10 @@ pub enum TcpStatistic { TailLossProbe, #[strum(serialize = "tcp/transmit/retransmit_timeout")] RetransmitTimeout, + #[strum(serialize = "tcp/receive/duplicate")] + Duplicate, + #[strum(serialize = "tcp/receive/out_of_order")] + OutOfOrder, } impl TcpStatistic { @@ -129,6 +133,8 @@ impl TcpStatistic { Self::Drop => Some("drop"), Self::TailLossProbe => Some("tlp"), Self::RetransmitTimeout => Some("rto"), + Self::Duplicate => Some("duplicate"), + Self::OutOfOrder => Some("ooo"), _ => None, } } @@ -232,6 +238,14 @@ impl TcpStatistic { binary_path: None, sub_system: None, }; + let tcp_validate_incoming_probe = Probe { + name: "tcp_validate_incoming".to_string(), + handler: "trace_validate_incoming".to_string(), + probe_type: ProbeType::Kernel, + probe_location: ProbeLocation::Entry, + binary_path: None, + sub_system: None, + }; // specify what probes are required for each telemetry. match self { @@ -253,6 +267,8 @@ impl TcpStatistic { Self::Drop => vec![tcp_drop_probe], Self::TailLossProbe => vec![tcp_tlp_probe], Self::RetransmitTimeout => vec![tcp_rto_probe], + Self::Duplicate => vec![tcp_validate_incoming_probe], + Self::OutOfOrder => vec![tcp_validate_incoming_probe], _ => Vec::new(), } }