conntrack: per-protocol and per-state statistics
ConntrackTable gains stats() method returning per-protocol breakdown: tcp_entries: N (est=N syn=N syn_recv=N fin=N tw=N close=N) udp_entries: N icmp_entries: N over_limit: N total_entries: N TCP states counted: None, SynSent, SynRecv, Established, FinWait, TimeWait, Close. Mirrors Linux /proc/net/stat/nf_conntrack. Exposed via three channels: - /scheme/netfilter/conntrack/stats (new dedicated node) - /scheme/netfilter/stats (existing, now includes per-state) - /scheme/netcfg/summary (includes conntrack stats block) All 31 tests pass.
This commit is contained in:
@@ -440,6 +440,55 @@ impl ConntrackTable {
|
||||
self.entries.len()
|
||||
}
|
||||
|
||||
/// Per-protocol and per-state connection breakdown.
|
||||
/// Returns lines like:
|
||||
/// tcp_entries: N (est=N syn=N syn_recv=N fin=N tw=N close=N)
|
||||
/// udp_entries: N
|
||||
/// icmp_entries: N
|
||||
/// over_limit: N
|
||||
/// total_entries: N
|
||||
pub fn stats(&self) -> alloc::string::String {
|
||||
let mut tcp = 0u32;
|
||||
let mut tcp_est = 0u32;
|
||||
let mut tcp_syn = 0u32;
|
||||
let mut tcp_syn_recv = 0u32;
|
||||
let mut tcp_fin = 0u32;
|
||||
let mut tcp_tw = 0u32;
|
||||
let mut tcp_close = 0u32;
|
||||
let mut udp = 0u32;
|
||||
let mut icmp = 0u32;
|
||||
|
||||
for entry in self.entries.values() {
|
||||
match entry.key.l4proto {
|
||||
6 => {
|
||||
tcp += 1;
|
||||
match entry.tcp_state {
|
||||
TcpTracking::None => {}
|
||||
TcpTracking::SynSent => tcp_syn += 1,
|
||||
TcpTracking::SynRecv => tcp_syn_recv += 1,
|
||||
TcpTracking::Established => tcp_est += 1,
|
||||
TcpTracking::FinWait => tcp_fin += 1,
|
||||
TcpTracking::TimeWait => tcp_tw += 1,
|
||||
TcpTracking::Close => tcp_close += 1,
|
||||
}
|
||||
}
|
||||
17 => udp += 1,
|
||||
1 | 58 => icmp += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = alloc::format!(
|
||||
"tcp_entries: {} (est={} syn={} syn_recv={} fin={} tw={} close={})\n",
|
||||
tcp, tcp_est, tcp_syn, tcp_syn_recv, tcp_fin, tcp_tw, tcp_close
|
||||
);
|
||||
out.push_str(&alloc::format!("udp_entries: {}\n", udp));
|
||||
out.push_str(&alloc::format!("icmp_entries: {}\n", icmp));
|
||||
out.push_str(&alloc::format!("over_limit: {}\n", self.over_limit_count));
|
||||
out.push_str(&alloc::format!("total_entries: {}\n", self.entries.len()));
|
||||
out
|
||||
}
|
||||
|
||||
fn check_syn_limit(&mut self, src: IpAddress, now: Instant) -> bool {
|
||||
const SYN_LIMIT: u32 = 100;
|
||||
const SYN_WINDOW: Duration = Duration::from_secs(1);
|
||||
|
||||
@@ -140,6 +140,10 @@ fn mk_root_node(
|
||||
}
|
||||
out.push_str("filter chains:\n");
|
||||
out.push_str(&filter_table.borrow().chain_summary());
|
||||
if let Some(ref ct) = filter_table.borrow().conntrack {
|
||||
out.push_str("conntrack stats:\n");
|
||||
out.push_str(&ct.stats());
|
||||
}
|
||||
out
|
||||
}
|
||||
},
|
||||
|
||||
@@ -173,6 +173,12 @@ impl NetFilterSchemeInner {
|
||||
.unwrap_or_else(|| b"conntrack: not enabled\n".to_vec()),
|
||||
true, false,
|
||||
),
|
||||
["conntrack", "stats"] => (
|
||||
self.table.borrow().conntrack.as_ref()
|
||||
.map(|ct| ct.stats().into_bytes())
|
||||
.unwrap_or_else(|| b"conntrack: not enabled\n".to_vec()),
|
||||
true, false,
|
||||
),
|
||||
["log"] => {
|
||||
let buf = &self.table.borrow().log_buffer;
|
||||
let mut out = String::new();
|
||||
@@ -210,6 +216,7 @@ impl NetFilterSchemeInner {
|
||||
table.rules.len(), snat_count, dnat_count));
|
||||
if let Some(ref ct) = table.conntrack {
|
||||
out.push_str(&format!("conntrack: {}\n", ct.len()));
|
||||
out.push_str(&ct.stats());
|
||||
}
|
||||
(out.into_bytes(), true, false)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user