mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Merge pull request #305 from LibreQoE/issue_302_piano_rolls
Issue 302/303/304 piano rolls
This commit is contained in:
commit
0f1986a258
@ -30,7 +30,7 @@ pub struct CakeDiffTinTransit {
|
||||
pub backlog_bytes: u32,
|
||||
pub drops: u32,
|
||||
pub marks: u32,
|
||||
pub avg_delay_us: u32,
|
||||
pub base_delay_us: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
|
||||
|
@ -94,7 +94,8 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<div id="raw"></div>
|
||||
<a href="#" class="btn btn-small btn-info" id="btnPause"><i class="fa fa-pause"></i> Pause</a>
|
||||
<a href="#" class="btn btn-small btn-info" id="btnSlow"><i class="fa fa-hourglass"></i> Slow Mode</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -304,8 +305,21 @@
|
||||
}
|
||||
|
||||
ingestDelays(subData, currentX, tin) {
|
||||
this.delays.store(tin, currentX, 0, subData[0][CDT.tins][tin][CDTT.avg_delay_us] * 0.001);
|
||||
this.delays.store(tin, currentX, 1, 0.0 - subData[1][CDT.tins][tin][CDTT.avg_delay_us] * 0.001);
|
||||
let down = subData[0][CDT.tins][tin][CDTT.avg_delay_us] * 0.001;
|
||||
let up = subData[1][CDT.tins][tin][CDTT.avg_delay_us] * 0.001;
|
||||
if (down == 0.0) {
|
||||
down = null;
|
||||
} else {
|
||||
down = Math.log10(down);
|
||||
}
|
||||
if (up == 0.0) {
|
||||
up = null;
|
||||
} else {
|
||||
//console.log(up);
|
||||
up = 0.0 - Math.log10(up);
|
||||
}
|
||||
this.delays.store(tin, currentX, 0, down);
|
||||
this.delays.store(tin, currentX, 1, up);
|
||||
}
|
||||
|
||||
ingestQueueLen(subData, currentX) {
|
||||
@ -374,7 +388,13 @@
|
||||
|
||||
if (this.backlogPlotted == null) {
|
||||
this.backlogPlotted = true;
|
||||
Plotly.newPlot(graph, graphData, { margin: { l: 0, r: 0, b: 0, t: 0, pad: 4 }, yaxis: { automargin: true, title: "Bytes" }, xaxis: { automargin: true, title: "Time since now" } });
|
||||
Plotly.newPlot(
|
||||
graph,
|
||||
graphData,
|
||||
{
|
||||
margin: { l: 0, r: 0, b: 0, t: 0, pad: 4 },
|
||||
yaxis: { automargin: true, title: "Bytes" },
|
||||
xaxis: { automargin: true, title: "Time since now" } });
|
||||
} else {
|
||||
Plotly.redraw(graph, graphData);
|
||||
}
|
||||
@ -390,7 +410,12 @@
|
||||
];
|
||||
|
||||
if (this.delaysPlotted == null) {
|
||||
Plotly.newPlot(graph, graphData, { margin: { l: 0, r: 0, b: 0, t: 0, pad: 4 }, yaxis: { automargin: true, title: "ms" }, xaxis: { automargin: true, title: "Time since now" } });
|
||||
Plotly.newPlot(
|
||||
graph,
|
||||
graphData,
|
||||
{ margin: { l: 8, r: 0, b: 0, t: 0, pad: 4 },
|
||||
yaxis: { automargin: true, title: "log10(ms)", range: [-1.0, 1.0] },
|
||||
xaxis: { automargin: true, title: "Time since now" } });
|
||||
this.delaysPlotted = true;
|
||||
} else {
|
||||
Plotly.redraw(graph, graphData);
|
||||
@ -520,10 +545,10 @@
|
||||
up = 0 - up;
|
||||
let down_slot = Math.floor((down / circuit_info[CircuitInfo.capacity][0]) * 10.0);
|
||||
let up_slot = Math.floor((up / circuit_info[CircuitInfo.capacity][1]) * 10.0);
|
||||
/*if (down_slot < 0) down_slot = 0;
|
||||
if (down_slot < 0) down_slot = 0;
|
||||
if (up_slot < 0) up_slot = 0;
|
||||
if (down_slot > 11) down_slot = 11;
|
||||
if (up_slot > 11) up_slot = 11;*/
|
||||
if (down_slot > 10) down_slot = 10;
|
||||
if (up_slot > 10) up_slot = 10;
|
||||
this.quantiles[0][down_slot] += 1;
|
||||
this.quantiles[1][up_slot] += 1;
|
||||
//console.log(down_slot, up_slot);
|
||||
@ -796,22 +821,50 @@
|
||||
|
||||
let id = 0;
|
||||
let activeTab = "pills-home-tab";
|
||||
var lastCalledTime;
|
||||
var fps;
|
||||
var worstDelta = 0;
|
||||
var paused = false;
|
||||
var slowMode = false;
|
||||
|
||||
function oneSecondCadence() {
|
||||
//console.log(activeTab);
|
||||
switch (activeTab) {
|
||||
case "pills-funnel-tab": {
|
||||
getFunnel();
|
||||
} break;
|
||||
case "pills-flows-tab": {
|
||||
getFlows();
|
||||
} break;
|
||||
default: {
|
||||
pollQueue();
|
||||
getThroughput();
|
||||
function showFps() {
|
||||
if(!lastCalledTime) {
|
||||
lastCalledTime = Date.now();
|
||||
fps = 0;
|
||||
return;
|
||||
}
|
||||
delta = (Date.now() - lastCalledTime)/1000;
|
||||
lastCalledTime = Date.now();
|
||||
fps = 1/delta;
|
||||
//$("#fps").text(fps.toFixed(0));
|
||||
worstDelta = Math.max(delta, worstDelta);
|
||||
}
|
||||
|
||||
function updateFrame() {
|
||||
showFps();
|
||||
if (!paused) {
|
||||
switch (activeTab) {
|
||||
case "pills-funnel-tab": {
|
||||
getFunnel();
|
||||
} break;
|
||||
case "pills-flows-tab": {
|
||||
getFlows();
|
||||
} break;
|
||||
default: {
|
||||
pollQueue();
|
||||
getThroughput();
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(oneSecondCadence, 1000);
|
||||
// Doing this to balance out the FPS
|
||||
// It will tend towards the slowest
|
||||
if (slowMode) {
|
||||
setTimeout(updateFrame, 1000);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(updateFrame);
|
||||
}, worstDelta * 200);
|
||||
}
|
||||
}
|
||||
|
||||
function wireUpTabEvents() {
|
||||
@ -822,8 +875,45 @@
|
||||
});
|
||||
}
|
||||
|
||||
function isSlowMode() {
|
||||
let slow = localStorage.getItem("slowMode");
|
||||
if (slow == null) {
|
||||
localStorage.setItem("slowMode", false);
|
||||
slow = false;
|
||||
}
|
||||
if (slow == "false") {
|
||||
slow = false;
|
||||
} else if (slow == "true") {
|
||||
slow = true;
|
||||
}
|
||||
return slow;
|
||||
}
|
||||
|
||||
function start() {
|
||||
wireUpTabEvents();
|
||||
$("#btnPause").on('click', () => {
|
||||
paused = !paused;
|
||||
if (paused) {
|
||||
$("#btnPause").html("<i class='fa fa-play'></i> Resume");
|
||||
} else {
|
||||
$("#btnPause").html("<i class='fa fa-pause'></i> Pause");
|
||||
}
|
||||
});
|
||||
slowMode = isSlowMode();
|
||||
if (slowMode) {
|
||||
$("#btnSlow").html("<i class='fa fa-fast-forward'></i> Fast Mode");
|
||||
} else {
|
||||
$("#btnSlow").html("<i class='fa fa-hourglass'></i> Slow Mode");
|
||||
}
|
||||
$("#btnSlow").on('click', () => {
|
||||
slowMode = !slowMode;
|
||||
localStorage.setItem("slowMode", slowMode);
|
||||
if (slowMode) {
|
||||
$("#btnSlow").html("<i class='fa fa-fast-forward'></i> Fast Mode");
|
||||
} else {
|
||||
$("#btnSlow").html("<i class='fa fa-hourglass'></i> Slow Mode");
|
||||
}
|
||||
});
|
||||
colorReloadButton();
|
||||
updateHostCounts();
|
||||
const params = new Proxy(new URLSearchParams(window.location.search), {
|
||||
@ -831,7 +921,8 @@
|
||||
});
|
||||
id = params.id;
|
||||
$.get("/api/watch_circuit/" + params.id, () => {
|
||||
oneSecondCadence();
|
||||
//updateFrame();
|
||||
requestAnimationFrame(updateFrame);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -73,11 +73,33 @@
|
||||
|
||||
<script>
|
||||
var packets = [];
|
||||
var flows = {};
|
||||
var pages = 0;
|
||||
var PAGE_SIZE = 1000;
|
||||
var target = "";
|
||||
var current_page = 0;
|
||||
var capacity = [];
|
||||
var activeFilter = null;
|
||||
var activeSet = null;
|
||||
var activeChart = 0;
|
||||
var activePage = 0;
|
||||
|
||||
function filter(newFilter) {
|
||||
activeFilter = newFilter;
|
||||
if (newFilter == null) {
|
||||
activeSet = packets;
|
||||
} else {
|
||||
activeSet = packets.filter(packet => packet.flow_id == activeFilter);
|
||||
}
|
||||
pages = Math.ceil((activeSet.length / PAGE_SIZE));
|
||||
paginator(0);
|
||||
viewPage(0);
|
||||
}
|
||||
|
||||
function setChart(n) {
|
||||
activeChart = n;
|
||||
paginator(activePage);
|
||||
viewPage(activePage);
|
||||
}
|
||||
|
||||
function proto(n) {
|
||||
switch (n) {
|
||||
@ -115,37 +137,80 @@ if (hdr->cwr) flags |= 128;
|
||||
|
||||
function zoomIn() {
|
||||
PAGE_SIZE /= 2;
|
||||
current_page /= 2;
|
||||
activePage /= 2;
|
||||
pages = packets.length / PAGE_SIZE;
|
||||
viewPage(current_page);
|
||||
viewPage(activePage);
|
||||
}
|
||||
|
||||
function zoomOut() {
|
||||
PAGE_SIZE *= 2;
|
||||
current_page *= 2;
|
||||
activePage *= 2;
|
||||
pages = packets.length / PAGE_SIZE;
|
||||
viewPage(current_page);
|
||||
viewPage(activePage);
|
||||
}
|
||||
|
||||
function paginator(active) {
|
||||
activePage = active;
|
||||
let paginator = "<a href='/api/pcap/" + target + "/capture-" + circuit_id + "-" + starting_timestamp + ".pcap' class='btn btn-warning'>Download PCAP Dump</a> ";
|
||||
paginator += "<a href='#' class='btn btn-info' onClick='zoomIn();'>Zoom In</a> ";
|
||||
paginator += "<a href='#' class='btn btn-info' onClick='zoomOut();'>Zoom Out</a> (ℹ️ Or drag an area of the graph) <br />";
|
||||
|
||||
paginator += "<div style='margin: 4px; padding: 6px; background-color: #ddd; border: solid 1px black;'>";
|
||||
paginator += "<strong>Jump to page</strong>: ";
|
||||
for (let i=0; i<pages; i++) {
|
||||
if (i == active) {
|
||||
paginator += " " + i + " ";
|
||||
} else {
|
||||
paginator += "<a href='#' onclick='viewPage(" + i + ");'>" + i + "</a> ";
|
||||
}
|
||||
paginator += "<select>"
|
||||
for (let i=0; i<pages; i++) {
|
||||
if (i == active) {
|
||||
paginator += "<option selected>" + i + "</option>";
|
||||
} else {
|
||||
paginator += "<option onclick='viewPage(" + i + ");'>" + i + "</option> ";
|
||||
}
|
||||
$("#pages").html(paginator);
|
||||
}
|
||||
paginator += "</select> | ";
|
||||
|
||||
// Offer flow filtering
|
||||
paginator += "<strong>Filter Flows</strong>: ";
|
||||
paginator += "<select>";
|
||||
if (activeFilter == null) {
|
||||
paginator += "<option selected onclick='filter(null);'>View All</option>";
|
||||
} else {
|
||||
paginator += "<option onclick='filter(null);'>View All</option>";
|
||||
}
|
||||
Object.keys(flows).forEach(key => {
|
||||
if (activeFilter == key) {
|
||||
paginator += "<option selected onclick='filter(\"" + key + "\");'>" + key + "</option>";
|
||||
} else {
|
||||
paginator += "<option onclick='filter(\"" + key + "\");'>" + key + "</option>";
|
||||
}
|
||||
});
|
||||
paginator += "</select> | ";
|
||||
|
||||
// Offer graph choices
|
||||
paginator += "<strong>Graph</strong>: ";
|
||||
paginator += "<select>";
|
||||
if (activeChart == 0) {
|
||||
paginator += "<option selected>Packet-Size Chart</option>";
|
||||
} else {
|
||||
paginator += "<option onclick='setChart(0);'>Packet-Size Chart</option>";
|
||||
}
|
||||
if (activeChart == 1) {
|
||||
paginator += "<option selected>Piano Roll Flow Chart</option>";
|
||||
} else {
|
||||
paginator += "<option onclick='setChart(1);'>Piano Roll Flow Chart</option>";
|
||||
}
|
||||
if (activeChart == 2) {
|
||||
paginator += "<option selected>TCP Window Chart</option>";
|
||||
} else {
|
||||
paginator += "<option onclick='setChart(2);'>TCP Window Chart</option>";
|
||||
}
|
||||
paginator += "</select>";
|
||||
paginator += "</div>";
|
||||
|
||||
$("#pages").html(paginator);
|
||||
}
|
||||
|
||||
function viewPage(n) {
|
||||
let start = n * PAGE_SIZE;
|
||||
let end = Math.min(start + PAGE_SIZE, packets.length);
|
||||
let end = Math.min(start + PAGE_SIZE, activeSet.length);
|
||||
if (start > packets.length) {
|
||||
console.log("OOps");
|
||||
}
|
||||
@ -156,46 +221,99 @@ if (hdr->cwr) flags |= 128;
|
||||
let y2_axis = [];
|
||||
for (let i=start; i<end; ++i) {
|
||||
html += "<tr>";
|
||||
html += "<td>" + packets[i].timestamp + "</td>";
|
||||
html += "<td>" + proto(packets[i].ip_protocol) + "</td>";
|
||||
html += "<td>" + activeSet[i].timestamp + "</td>";
|
||||
html += "<td>" + proto(activeSet[i].ip_protocol) + "</td>";
|
||||
|
||||
if (packets[i].ip_protocol == 6) {
|
||||
html += "<td>" + tcp_flags(packets[i].tcp_flags) + "</td>";
|
||||
html += "<td>" + packets[i].tcp_tsval + "/" + packets[i].tcp_tsecr + "</td>";
|
||||
html += "<td>" + packets[i].tcp_window + "</td>";
|
||||
if (activeSet[i].ip_protocol == 6) {
|
||||
html += "<td>" + tcp_flags(activeSet[i].tcp_flags) + "</td>";
|
||||
html += "<td>" + activeSet[i].tcp_tsval + "/" + activeSet[i].tcp_tsecr + "</td>";
|
||||
html += "<td>" + activeSet[i].tcp_window + "</td>";
|
||||
} else {
|
||||
html += "<td></td><td></td><td></td>";
|
||||
}
|
||||
|
||||
if (packets[i].ip_protocol != 1) {
|
||||
html += "<td>" + packets[i].src + ":" + packets[i].src_port + " -> " + packets[i].dst + ":" + packets[i].dst_port + "</td>";
|
||||
if (activeSet[i].ip_protocol != 1) {
|
||||
html += "<td>" + activeSet[i].src + ":" + activeSet[i].src_port + " -> " + activeSet[i].dst + ":" + activeSet[i].dst_port + "</td>";
|
||||
} else {
|
||||
html += "<td>" + packets[i].src + " -> " + packets[i].dst + "</td>";
|
||||
html += "<td>" + activeSet[i].src + " -> " + activeSet[i].dst + "</td>";
|
||||
}
|
||||
html += "<td>" + packets[i].size + "</td>";
|
||||
html += "<td>" + ecn(packets[i].ecn) + "</td>";
|
||||
html += "<td>0x" + packets[i].dscp.toString(16) + "</td>";
|
||||
html += "<td>" + activeSet[i].size + "</td>";
|
||||
html += "<td>" + ecn(activeSet[i].ecn) + "</td>";
|
||||
html += "<td>0x" + activeSet[i].dscp.toString(16) + "</td>";
|
||||
html += "</tr>";
|
||||
x_axis.push(packets[i].timestamp);
|
||||
if (packets[i].src == target) {
|
||||
y1_axis.push(packets[i].size);
|
||||
x_axis.push(activeSet[i].timestamp);
|
||||
if (activeSet[i].src == target) {
|
||||
y1_axis.push(activeSet[i].size);
|
||||
y2_axis.push(0);
|
||||
} else {
|
||||
y1_axis.push(0);
|
||||
y2_axis.push(0.0 - packets[i].size);
|
||||
y2_axis.push(0.0 - activeSet[i].size);
|
||||
}
|
||||
}
|
||||
html += "</table>";
|
||||
$("#dump").html(html);
|
||||
paginator(n);
|
||||
|
||||
// Make the graph
|
||||
// Make the graph
|
||||
let graph = document.getElementById("graph");
|
||||
let data = [
|
||||
{x: x_axis, y:y1_axis, name: 'Download', type: 'scatter', mode: 'markers', error_x: { type: 'percent', value: capacity[0], symetric: false, valueminus: 0 }},
|
||||
{x: x_axis, y:y2_axis, name: 'Upload', type: 'scatter', mode: 'markers', error_x: { type: 'percent', value: capacity[1], symetric: false, valueminus: 0 }},
|
||||
];
|
||||
Plotly.newPlot(graph, data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true, title: 'Bytes' }, xaxis: {automargin: true, title: "Nanoseconds"} }, { responsive: true });
|
||||
if (activeChart == 0) {
|
||||
// Render the timeline chart
|
||||
let data = [
|
||||
{x: x_axis, y:y1_axis, name: 'Download', type: 'scatter', mode: 'markers', error_x: { type: 'percent', value: capacity[0], symetric: false, valueminus: 0 }},
|
||||
{x: x_axis, y:y2_axis, name: 'Upload', type: 'scatter', mode: 'markers', error_x: { type: 'percent', value: capacity[1], symetric: false, valueminus: 0 }},
|
||||
];
|
||||
Plotly.newPlot(graph, data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true, title: 'Bytes' }, xaxis: {automargin: true, title: "Nanoseconds"} }, { responsive: true });
|
||||
} else if (activeChart == 1) {
|
||||
// Render the piano roll chart
|
||||
let flowGraphY = {};
|
||||
for (var i=start; i<end; ++i) {
|
||||
let flow_id = activeSet[i].flow_id;
|
||||
if (flowGraphY.hasOwnProperty(flow_id)) {
|
||||
flowGraphY[flow_id].x.push(activeSet[i].timestamp);
|
||||
flowGraphY[flow_id].y.push(flows[flow_id].flowCounter);
|
||||
} else {
|
||||
flowGraphY[flow_id] = {
|
||||
"x": [ activeSet[i].timestamp ],
|
||||
"y": [ flows[flow_id].flowCounter ],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let data = [];
|
||||
for (flow in flowGraphY) {
|
||||
//console.log(flowGraphY[flow]);
|
||||
data.push({
|
||||
x: flowGraphY[flow].x, y: flowGraphY[flow].y, name: flow, type: 'scatter', mode: 'markers',
|
||||
});
|
||||
}
|
||||
Plotly.newPlot(graph, data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true, title: 'Flow' }, xaxis: {automargin: true, title: "Nanoseconds"} }, { responsive: true });
|
||||
} else if (activeChart == 2) {
|
||||
// Render the window chart
|
||||
let flowGraphY = {};
|
||||
for (var i=start; i<end; ++i) {
|
||||
let flow_id = activeSet[i].flow_id;
|
||||
if (flow_id.includes("TCP")) {
|
||||
if (flowGraphY.hasOwnProperty(flow_id)) {
|
||||
flowGraphY[flow_id].x.push(activeSet[i].timestamp);
|
||||
flowGraphY[flow_id].y.push(activeSet[i].tcp_window);
|
||||
} else {
|
||||
flowGraphY[flow_id] = {
|
||||
"x": [ activeSet[i].timestamp ],
|
||||
"y": [ activeSet[i].tcp_window ],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let data = [];
|
||||
for (flow in flowGraphY) {
|
||||
//console.log(flowGraphY[flow]);
|
||||
data.push({
|
||||
x: flowGraphY[flow].x, y: flowGraphY[flow].y, name: flow, type: 'scatter', mode: 'markers',
|
||||
});
|
||||
}
|
||||
Plotly.newPlot(graph, data, { margin: { l:0,r:0,b:0,t:0,pad:4 }, yaxis: { automargin: true, title: 'Window Size' }, xaxis: {automargin: true, title: "Nanoseconds"} }, { responsive: true });
|
||||
}
|
||||
}
|
||||
|
||||
let circuit_id = null;
|
||||
@ -217,17 +335,32 @@ if (hdr->cwr) flags |= 128;
|
||||
target = params.id;
|
||||
$.get("/api/packet_dump/" + params.id, (data) => {
|
||||
data.sort((a,b) => a.timestamp - b.timestamp);
|
||||
let min_ts = null;
|
||||
for (let i=0; i<data.length; ++i) {
|
||||
if (min_ts == null || min_ts > data[i].timestamp) {
|
||||
min_ts = data[i].timestamp;
|
||||
|
||||
// Find the minimum timestamp
|
||||
let min_ts = data.reduce((prev, curr) => prev.timestamp < curr.timestamp ? prev : curr).timestamp;
|
||||
|
||||
// Set the displayed timestamp to be (ts - min)
|
||||
data.forEach(packet => packet.timestamp -= min_ts);
|
||||
|
||||
// Divide the packets into flows and append the flow_id
|
||||
let flowCounter = 0;
|
||||
data.forEach(packet => {
|
||||
let flow_id = proto(packet.ip_protocol) + " " + packet.src + ":" + packet.src_port + " <-> " + packet.dst + ":" + packet.dst_port;
|
||||
let reverse_flow_id = proto(packet.ip_protocol) + " " + packet.dst + ":" + packet.dst_port + " <-> " + packet.src + ":" + packet.src_port;
|
||||
if (flows.hasOwnProperty(flow_id)) {
|
||||
packet.flow_id = flow_id;
|
||||
} else if (flows.hasOwnProperty(reverse_flow_id)) {
|
||||
packet.flow_id = reverse_flow_id;
|
||||
} else {
|
||||
flows[flow_id] = { flowCounter };
|
||||
packet.flow_id = flow_id;
|
||||
flowCounter++;
|
||||
}
|
||||
}
|
||||
for (let i=0; i<data.length; ++i) {
|
||||
data[i].timestamp -= min_ts;
|
||||
}
|
||||
});
|
||||
|
||||
packets = data;
|
||||
pages = Math.ceil((packets.length / PAGE_SIZE));
|
||||
activeSet = packets;
|
||||
pages = Math.ceil((activeSet.length / PAGE_SIZE));
|
||||
starting_timestamp = min_ts;
|
||||
paginator(0);
|
||||
viewPage(0);
|
||||
|
@ -46,7 +46,7 @@ pub struct CakeDiffTin {
|
||||
pub backlog_bytes: u32,
|
||||
pub drops: u32,
|
||||
pub marks: u32,
|
||||
pub avg_delay_us: u32,
|
||||
pub base_delay_us: u32,
|
||||
}
|
||||
|
||||
fn cake_diff(
|
||||
@ -65,7 +65,7 @@ fn cake_diff(
|
||||
backlog_bytes: new.backlog_bytes,
|
||||
drops: new.drops.saturating_sub(prev.drops),
|
||||
marks: new.ecn_marks.saturating_sub(prev.ecn_marks),
|
||||
avg_delay_us: new.avg_delay_us,
|
||||
base_delay_us: new.base_delay_us,
|
||||
})
|
||||
.collect();
|
||||
return Ok(QueueDiff::Cake(CakeDiff {
|
||||
|
@ -101,7 +101,7 @@ impl Into<CakeDiffTinTransit> for CakeDiffTin {
|
||||
backlog_bytes: self.backlog_bytes,
|
||||
drops: self.drops,
|
||||
marks: self.marks,
|
||||
avg_delay_us: self.avg_delay_us,
|
||||
base_delay_us: self.base_delay_us,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user