mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Continue cleaning up flow display system.
This commit is contained in:
parent
64641c6849
commit
4372b501c9
@ -88,5 +88,5 @@ pub enum BusResponse {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// Flow Data
|
/// Flow Data
|
||||||
FlowData(Vec<FlowTransport>),
|
FlowData(Vec<(FlowTransport, Option<FlowTransport>)>),
|
||||||
}
|
}
|
||||||
|
@ -81,5 +81,16 @@ pub struct FlowTransport {
|
|||||||
pub dst_port: u16,
|
pub dst_port: u16,
|
||||||
pub bytes: u64,
|
pub bytes: u64,
|
||||||
pub packets: u64,
|
pub packets: u64,
|
||||||
pub tos: u8,
|
pub dscp: u8,
|
||||||
|
pub congestion: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tos_parser(tos: u8) -> (u8, bool) {
|
||||||
|
// Format: 2 bits of ECN, 6 bits of DSCP
|
||||||
|
const ECN: u8 = 0b00000011;
|
||||||
|
const DSCP: u8 = 0b11111100;
|
||||||
|
|
||||||
|
let ecn = tos & ECN;
|
||||||
|
let dscp = (tos & DSCP) >> 2;
|
||||||
|
(dscp, ecn == 3)
|
||||||
}
|
}
|
@ -12,7 +12,7 @@
|
|||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
mod bus;
|
mod bus;
|
||||||
mod ip_stats;
|
mod ip_stats;
|
||||||
pub use ip_stats::{IpMapping, IpStats, XdpPpingResult, FlowProto, FlowTransport};
|
pub use ip_stats::{IpMapping, IpStats, XdpPpingResult, FlowProto, FlowTransport, tos_parser};
|
||||||
mod tc_handle;
|
mod tc_handle;
|
||||||
pub use bus::{
|
pub use bus::{
|
||||||
bus_request, decode_request, decode_response, encode_request,
|
bus_request, decode_request, decode_response, encode_request,
|
||||||
|
@ -100,7 +100,7 @@ pub async fn raw_queue_by_circuit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[get("/api/flows/<ip_list>")]
|
#[get("/api/flows/<ip_list>")]
|
||||||
pub async fn flow_stats(ip_list: String, _auth: AuthGuard) -> NoCache<Json<Vec<FlowTransport>>> {
|
pub async fn flow_stats(ip_list: String, _auth: AuthGuard) -> NoCache<Json<Vec<(FlowTransport, Option<FlowTransport>)>>> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let request: Vec<BusRequest> = ip_list.split(',').map(|ip| BusRequest::GetFlowStats(ip.to_string())).collect();
|
let request: Vec<BusRequest> = ip_list.split(',').map(|ip| BusRequest::GetFlowStats(ip.to_string())).collect();
|
||||||
let responses = bus_request(request).await.unwrap();
|
let responses = bus_request(request).await.unwrap();
|
||||||
|
@ -537,15 +537,56 @@
|
|||||||
}
|
}
|
||||||
ip_list = ip_list.substring(0, ip_list.length-1);
|
ip_list = ip_list.substring(0, ip_list.length-1);
|
||||||
$.get("/api/flows/" + ip_list, (data) => {
|
$.get("/api/flows/" + ip_list, (data) => {
|
||||||
|
//console.log(data);
|
||||||
let html = "<table class='table table-striped'>";
|
let html = "<table class='table table-striped'>";
|
||||||
html += "<thead><th>Protocol</th><th>Flow</th><th>Packets</th><th>Bytes</th></thead><tbody>";
|
html += "<thead>";
|
||||||
|
html += "<th>Protocol</th>";
|
||||||
|
html += "<th>Source</th>";
|
||||||
|
html += "<th>Source Port</th>";
|
||||||
|
html += "<th>Dest</th>";
|
||||||
|
html += "<th>Dest Port</th>";
|
||||||
|
html += "<th>Packets In</th>";
|
||||||
|
html += "<th>Packets Out</th>";
|
||||||
|
html += "<th>Bytes In</th>";
|
||||||
|
html += "<th>Bytes Out</th>";
|
||||||
|
html += "<th>DSCP In</th>";
|
||||||
|
html += "<th>DSCP Out</th>";
|
||||||
|
html += "<th>ECN In</th>";
|
||||||
|
html += "<th>ECN Out</th>";
|
||||||
|
html += "</thead>";
|
||||||
for (let i=0; i<data.length; i++) {
|
for (let i=0; i<data.length; i++) {
|
||||||
|
let rpackets = "-";
|
||||||
|
let rbytes = "-";
|
||||||
|
let rdscp = "-";
|
||||||
|
let rcongestion = false;
|
||||||
|
if (data[i][1] != null) {
|
||||||
|
rpackets = data[i][1].packets;
|
||||||
|
rbytes = scaleNumber(data[i][1].bytes);
|
||||||
|
rdscp = "0x" + data[i][1].dscp.toString(16);
|
||||||
|
rcongestion = data[i][1].congestion;
|
||||||
|
}
|
||||||
html += "<tr>";
|
html += "<tr>";
|
||||||
html += "<td>" + data[i].proto + "</td>";
|
html += "<td>" + data[i][0].proto + "</td>";
|
||||||
html += "<td>" + data[i].src + ":" + data[i].src_port + "▶️" + data[i].dst + ":" + data[i].dst_port + "</td>";
|
html += "<td>" + data[i][0].src + "</td>";
|
||||||
html += "<td>" + data[i].packets + "</td>";
|
html += "<td>" + data[i][0].src_port + "</td>";
|
||||||
html += "<td>" + scaleNumber(data[i].bytes) + "</td>";
|
html += "<td>" + data[i][0].dst + "</td>";
|
||||||
html += "<td>" + data[i].tos + "</td>";
|
html += "<td>" + data[i][0].dst_port + "</td>";
|
||||||
|
html += "<td>" + data[i][0].packets + "</td>";
|
||||||
|
html += "<td>" + rpackets + "</td>";
|
||||||
|
html += "<td>" + scaleNumber(data[i][0].bytes) + "</td>";
|
||||||
|
html += "<td>" + rbytes + "</td>";
|
||||||
|
html += "<td>0x" + data[i][0].dscp.toString(16) + "</td>";
|
||||||
|
html += "<td>" + rdscp + "</td>";
|
||||||
|
if (data[i][0].congestion) {
|
||||||
|
html += "<td>❌</td>";
|
||||||
|
} else {
|
||||||
|
html += "<td>-</td>";
|
||||||
|
}
|
||||||
|
if (rcongestion) {
|
||||||
|
html += "<td>❌</td>";
|
||||||
|
} else {
|
||||||
|
html += "<td>-</td>";
|
||||||
|
}
|
||||||
html += "</tr>";
|
html += "</tr>";
|
||||||
}
|
}
|
||||||
html += "</tbody></table>";
|
html += "</tbody></table>";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{time::Duration, net::IpAddr};
|
use std::{time::Duration, net::IpAddr, collections::HashSet};
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use lqos_bus::{BusResponse, FlowTransport};
|
use lqos_bus::{BusResponse, FlowTransport, tos_parser};
|
||||||
use lqos_sys::{HeimdallData, HeimdallKey, XdpIpAddress, heimdall_watch_ip};
|
use lqos_sys::{HeimdallData, HeimdallKey, XdpIpAddress, heimdall_watch_ip};
|
||||||
use lqos_utils::unix_time::time_since_boot;
|
use lqos_utils::unix_time::time_since_boot;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
@ -54,9 +54,7 @@ impl PalantirMonitor {
|
|||||||
flow.bytes = combined.bytes;
|
flow.bytes = combined.bytes;
|
||||||
flow.packets = combined.packets;
|
flow.packets = combined.packets;
|
||||||
flow.last_seen = combined.last_seen;
|
flow.last_seen = combined.last_seen;
|
||||||
if combined.tos != 0 {
|
|
||||||
flow.tos = combined.tos;
|
flow.tos = combined.tos;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Insert
|
// Insert
|
||||||
self.data.insert(key.clone(), combined);
|
self.data.insert(key.clone(), combined);
|
||||||
@ -93,10 +91,13 @@ pub fn get_flow_stats(ip: &str) -> BusResponse {
|
|||||||
heimdall_watch_ip(ip);
|
heimdall_watch_ip(ip);
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
// Obtain all the flows
|
||||||
|
let mut all_flows = Vec::new();
|
||||||
for value in HEIMDALL.data.iter() {
|
for value in HEIMDALL.data.iter() {
|
||||||
let key = value.key();
|
let key = value.key();
|
||||||
if key.src_ip == ip || key.dst_ip == ip {
|
if key.src_ip == ip || key.dst_ip == ip {
|
||||||
result.push(FlowTransport{
|
let (dscp, congestion) = tos_parser(value.tos);
|
||||||
|
all_flows.push(FlowTransport{
|
||||||
src: key.src_ip.as_ip().to_string(),
|
src: key.src_ip.as_ip().to_string(),
|
||||||
dst: key.dst_ip.as_ip().to_string(),
|
dst: key.dst_ip.as_ip().to_string(),
|
||||||
src_port: key.src_port,
|
src_port: key.src_port,
|
||||||
@ -108,11 +109,29 @@ pub fn get_flow_stats(ip: &str) -> BusResponse {
|
|||||||
},
|
},
|
||||||
bytes: value.bytes,
|
bytes: value.bytes,
|
||||||
packets: value.packets,
|
packets: value.packets,
|
||||||
tos: value.tos,
|
dscp,
|
||||||
|
congestion
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Turn them into reciprocal pairs
|
||||||
|
let mut done = HashSet::new();
|
||||||
|
for (i,flow) in all_flows.iter().enumerate() {
|
||||||
|
if !done.contains(&i) {
|
||||||
|
let flow_a = flow.clone();
|
||||||
|
let flow_b = if let Some(flow_b) = all_flows.iter().position(|f| f.src == flow_a.dst && f.src_port == flow_a.dst_port) {
|
||||||
|
done.insert(flow_b);
|
||||||
|
Some(all_flows[flow_b].clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push((flow_a, flow_b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return BusResponse::FlowData(result);
|
return BusResponse::FlowData(result);
|
||||||
}
|
}
|
||||||
BusResponse::Fail("No Stats or bad IP".to_string())
|
BusResponse::Fail("No Stats or bad IP".to_string())
|
||||||
|
Loading…
Reference in New Issue
Block a user