mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Real-time reloading of lqosd tunables and queue check frequency
Extends the bus to include a "reload lqosd" command that reloads the tunables and queue frequency in real-time, without requiring a bridge restart.
This commit is contained in:
parent
7b18ca4196
commit
7b0715756f
54
src/rust/Cargo.lock
generated
54
src/rust/Cargo.lock
generated
@ -205,15 +205,6 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.3"
|
||||
@ -386,7 +377,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"sha2 0.10.6",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"time",
|
||||
"version_check",
|
||||
@ -408,6 +399,17 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "cow_struct"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "780363852334e8717416de3477ac2ce707bdf91c086daae09b80f0b354b5a6b5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.5"
|
||||
@ -607,22 +609,13 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer 0.10.3",
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
@ -930,7 +923,7 @@ version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest 0.10.6",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1222,6 +1215,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"cc",
|
||||
"lqos_config",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -1234,7 +1228,7 @@ dependencies = [
|
||||
"ip_network",
|
||||
"ip_network_table",
|
||||
"serde",
|
||||
"sha2 0.9.9",
|
||||
"sha2",
|
||||
"toml",
|
||||
"uuid",
|
||||
]
|
||||
@ -1287,6 +1281,7 @@ name = "lqosd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cow_struct",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"log",
|
||||
@ -2098,19 +2093,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.6"
|
||||
@ -2119,7 +2101,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.10.6",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11,6 +11,7 @@ equinix_tests = []
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
bincode = "1"
|
||||
anyhow = "1"
|
||||
lqos_config = { path = "../lqos_config" }
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.0"
|
||||
|
@ -1,3 +1,4 @@
|
||||
use lqos_config::Tunables;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::TcHandle;
|
||||
|
||||
@ -83,6 +84,9 @@ pub enum BusRequest {
|
||||
/// Retrieve raw queue data for a given circuit ID.
|
||||
GetRawQueueData(String), // The string is the circuit ID
|
||||
|
||||
/// Requests a real-time adjustment of the `lqosd` tuning settings
|
||||
UpdateLqosDTuning(u64, Tunables),
|
||||
|
||||
/// If running on Equinix (the `equinix_test` feature is enabled),
|
||||
/// display a "run bandwidht test" link.
|
||||
#[cfg(feature = "equinix_tests")]
|
||||
|
@ -25,7 +25,7 @@ pub struct EtcLqos {
|
||||
|
||||
/// Represents a set of `sysctl` and `ethtool` tweaks that may be
|
||||
/// applied (in place of the previous version's offload service)
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||
pub struct Tunables {
|
||||
/// Should the `irq_balance` system service be stopped?
|
||||
pub stop_irq_balance: bool,
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::{auth_guard::AuthGuard, cache_control::NoCache};
|
||||
use default_net::get_interfaces;
|
||||
use lqos_config::{EtcLqos, LibreQoSConfig};
|
||||
use rocket::{fs::NamedFile, serde::json::Json};
|
||||
use lqos_bus::{BUS_BIND_ADDRESS, BusSession, BusRequest, encode_request, decode_response};
|
||||
use lqos_config::{EtcLqos, LibreQoSConfig, Tunables};
|
||||
use rocket::{fs::NamedFile, serde::json::Json, tokio::{net::TcpStream, io::{AsyncReadExt, AsyncWriteExt}}};
|
||||
|
||||
// Note that NoCache can be replaced with a cache option
|
||||
// once the design work is complete.
|
||||
@ -43,3 +44,27 @@ pub async fn update_python_config(_auth: AuthGuard, config: Json<LibreQoSConfig>
|
||||
config.save().unwrap();
|
||||
Json("OK".to_string())
|
||||
}
|
||||
|
||||
#[post("/api/lqos_tuning/<period>", data = "<tuning>")]
|
||||
pub async fn update_lqos_tuning(auth: AuthGuard, period: u64, tuning: Json<Tunables>) -> Json<String> {
|
||||
if auth != AuthGuard::Admin {
|
||||
return Json("Error: Not authorized".to_string());
|
||||
}
|
||||
|
||||
// Send the update to the server
|
||||
let mut stream = TcpStream::connect(BUS_BIND_ADDRESS).await.unwrap();
|
||||
let test = BusSession {
|
||||
auth_cookie: 1234,
|
||||
requests: vec![BusRequest::UpdateLqosDTuning(period, (*tuning).clone())],
|
||||
};
|
||||
let msg = encode_request(&test).unwrap();
|
||||
stream.write(&msg).await.unwrap();
|
||||
|
||||
// Receive reply
|
||||
let mut buf = Vec::new();
|
||||
let _ = stream.read_to_end(&mut buf).await.unwrap();
|
||||
let _reply = decode_response(&buf).unwrap();
|
||||
// For now, ignore the reply.
|
||||
|
||||
Json("OK".to_string())
|
||||
}
|
@ -58,6 +58,7 @@ fn rocket() -> _ {
|
||||
config_control::get_current_python_config,
|
||||
config_control::get_current_lqosd_config,
|
||||
config_control::update_python_config,
|
||||
config_control::update_lqos_tuning,
|
||||
auth_guard::create_first_user,
|
||||
auth_guard::login,
|
||||
auth_guard::admin_check,
|
||||
|
@ -58,9 +58,7 @@
|
||||
|
||||
<div class="col-sm-8 mx-auto" style="padding: 4px; margin-bottom: 4px;" id="controls">
|
||||
<a href="#" class="btn btn-primary" id="btnSaveIspConfig"><i class="fa fa-save"></i> Save ispConfig.py</a>
|
||||
<a href="#" class="btn btn-danger"><i class="fa fa-save"></i> Save /etc/lqos</a>
|
||||
<a href="#" class="btn btn-primary"><i class="fa fa-refresh"></i> Reload LibreQoS</a>
|
||||
<a href="#" class="btn btn-danger"><i class="fa fa-refresh"></i> (Re)Start lqosd</a>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-start">
|
||||
@ -127,7 +125,12 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><h3>Bifrost XDP-Accelerated Bridge</h3></td>
|
||||
<td colspan="2">
|
||||
<h3>Bifrost XDP-Accelerated Bridge</h3>
|
||||
<p class="alert alert-danger" role="alert">
|
||||
You must configure XDP bridging by editing the `/etc/lqos` file on the server.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="alert alert-warning" role="alert">
|
||||
@ -138,7 +141,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<input class="form-check-input" type="checkbox" value="" id="useKernelBridge">
|
||||
<input class="form-check-input" type="checkbox" value="" id="useKernelBridge" disabled="true">
|
||||
<label class="form-check-label" for="useKernelBridge">
|
||||
Enable Bifrost Acceleration
|
||||
</label>
|
||||
@ -230,20 +233,6 @@
|
||||
<div class="tab-pane fade" id="v-pills-server" role="tabpanel" aria-labelledby="v-pills-server-tab">
|
||||
<h2><i class="fa fa-server"></i> Server Settings</h2>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td colspan="2" class="alert-info" role="alert">
|
||||
How frequently should the TC queues be polled? 30-50 is good for detailed analysis,
|
||||
1000 is good for normal running.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Queue Check Frequency (ms)
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" min="10" max="1000" id="queuecheckms" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="alert-danger">
|
||||
<i class="fa fa-warning"></i> Disabling actual shell commands stops LibreQoS from actually doing anything. Simulated
|
||||
@ -292,6 +281,22 @@
|
||||
<p>These settings can drastically affect performance of your server, including rendering it non-functional.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" class="alert-info" role="alert">
|
||||
How frequently should the TC queues be polled? 30-50 is good for detailed analysis,
|
||||
1000 is good for normal running. If you select a value slower than the time currently taken
|
||||
to access queue information, queue analysis will no longer display data on a consistent
|
||||
time-step. Values less than 20ms are not recommended.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Queue Check Frequency (ms)
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" min="10" max="1000" id="queuecheckms" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td colspan="2">IRQ Balancing should generally be disabled.</td></tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
@ -345,6 +350,12 @@
|
||||
<td><input type="text" id="disableOffloadList" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p class="alert alert-info" role="alert">
|
||||
At this time, you can only apply these settings to the current running instance. Edit <em>/etc/lqos</em> to
|
||||
apply changes permanently. Applying tuning settings will not restart your XDP bridge.
|
||||
</p>
|
||||
<a class="btn btn-secondary" id="btnApplyTuning">Apply Tuning Settings</a>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="v-pills-spylnx" role="tabpanel" aria-labelledby="v-pills-spylnx-tab">
|
||||
Spylnx Settings
|
||||
@ -440,13 +451,13 @@
|
||||
html += "<tbody>";
|
||||
for (let i=0; i<lqosd_config.bridge.interface_mapping.length; i++) {
|
||||
html += "<tr>";
|
||||
html += "<td>" + buildNICList('bfIn_' + i, lqosd_config.bridge.interface_mapping[i].name) + "</td>";
|
||||
html += "<td>" + buildNICList('bfOut_' + i, lqosd_config.bridge.interface_mapping[i].redirect_to) + "</td>";
|
||||
html += "<td>" + buildNICList('bfIn_' + i, lqosd_config.bridge.interface_mapping[i].name, true) + "</td>";
|
||||
html += "<td>" + buildNICList('bfOut_' + i, lqosd_config.bridge.interface_mapping[i].redirect_to, true) + "</td>";
|
||||
html += "<td><input type='checkbox' class='form-check-input' id='bfScanVLAN_" + i + "'";
|
||||
if (lqosd_config.bridge.interface_mapping[i].scan_vlans) {
|
||||
html += ' checked';
|
||||
}
|
||||
html += "/></td>";
|
||||
html += " disabled='true' /></td>";
|
||||
html += "</tr>";
|
||||
}
|
||||
html += "</tbody></table>";
|
||||
@ -459,9 +470,9 @@
|
||||
html += "<tbody>";
|
||||
for (let i=0; i<lqosd_config.bridge.vlan_mapping.length; i++) {
|
||||
html += "<tr>";
|
||||
html += "<td>" + buildNICList('bfvlanif_' + i, lqosd_config.bridge.vlan_mapping[i].parent) + "</td>";
|
||||
html += "<td><input id='bfvlantag_" + i + "' type='number' min='0' max='4094' value='" + lqosd_config.bridge.vlan_mapping[i].tag + "' /></td>";
|
||||
html += "<td><input id='bfvlanout_" + i + "' type='number' min='0' max='4094' value='" + lqosd_config.bridge.vlan_mapping[i].redirect_to + "' /></td>";
|
||||
html += "<td>" + buildNICList('bfvlanif_' + i, lqosd_config.bridge.vlan_mapping[i].parent, true) + "</td>";
|
||||
html += "<td><input id='bfvlantag_" + i + "' type='number' min='0' max='4094' value='" + lqosd_config.bridge.vlan_mapping[i].tag + "' disabled='true' /></td>";
|
||||
html += "<td><input id='bfvlanout_" + i + "' type='number' min='0' max='4094' value='" + lqosd_config.bridge.vlan_mapping[i].redirect_to + "' disabled='true' /></td>";
|
||||
html += "</tr>";
|
||||
}
|
||||
html += "</tbody></table>";
|
||||
@ -494,6 +505,7 @@
|
||||
// User management
|
||||
if (is_admin) {
|
||||
userManager();
|
||||
tuning();
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -506,6 +518,34 @@
|
||||
$("#userManager").html(html);
|
||||
}
|
||||
|
||||
function tuning() {
|
||||
$("#btnApplyTuning").on('click', () => {
|
||||
let period = Number($("#queuecheckms").val());
|
||||
let new_config = {
|
||||
stop_irq_balance: $("#stopIrqBalance").prop('checked'),
|
||||
netdev_budget_usecs: Number($("#netDevUsec").val()),
|
||||
netdev_budget_packets: Number($("#netDevPackets").val()),
|
||||
rx_usecs: Number($("#rxUsecs").val()),
|
||||
tx_usecs: Number($("#txUsecs").val()),
|
||||
disable_rxvlan: $("#disableRxVlan").prop('checked'),
|
||||
disable_txvlan: $("#disableTxVlan").prop('checked'),
|
||||
disable_offload: $("#disableOffloadList").val().split(' ')
|
||||
};
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/api/lqos_tuning/" + period,
|
||||
data: JSON.stringify(new_config),
|
||||
success: (data) => {
|
||||
if (data == "ERROR") {
|
||||
alert("Unable to apply settings.")
|
||||
} else {
|
||||
alert("Settings Applied");
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function fillNicList(id, selected) {
|
||||
let select = $("#" + id);
|
||||
let html = "";
|
||||
@ -520,8 +560,10 @@
|
||||
select.html(html);
|
||||
}
|
||||
|
||||
function buildNICList(id, selected) {
|
||||
let html = "<select id='" + id + "'>";
|
||||
function buildNICList(id, selected, disabled=false) {
|
||||
let html = "<select id='" + id + "'";
|
||||
if (disabled) html += " disabled='true' ";
|
||||
html += ">";
|
||||
for (i=0; i<nics.length; i++) {
|
||||
html += "<option value=\"";
|
||||
html += nics[i][0] + "\"";
|
||||
|
@ -21,3 +21,4 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
notify = { version = "5.0.0", default-features = false, feature=["macos_kqueue"] } # Not using crossbeam because of Tokio
|
||||
env_logger = "0"
|
||||
log = "0"
|
||||
cow_struct = "0"
|
||||
|
@ -6,7 +6,7 @@ mod offloads;
|
||||
mod program_control;
|
||||
mod queue_tracker;
|
||||
mod throughput_tracker;
|
||||
use crate::ip_mapping::{clear_ip_flows, del_ip_flow, list_mapped_ips, map_ip_to_flow};
|
||||
use crate::{ip_mapping::{clear_ip_flows, del_ip_flow, list_mapped_ips, map_ip_to_flow}, queue_tracker::QUEUE_MONITOR_INTERVAL};
|
||||
use anyhow::Result;
|
||||
use log::{info, warn};
|
||||
use lqos_bus::{
|
||||
@ -116,6 +116,19 @@ async fn main() -> Result<()> {
|
||||
BusRequest::GetRawQueueData(circuit_id) => {
|
||||
queue_tracker::get_raw_circuit_data(&circuit_id)
|
||||
}
|
||||
BusRequest::UpdateLqosDTuning(interval, tuning) => {
|
||||
// Real-time tuning changes. Probably dangerous.
|
||||
if let Ok(config) = LibreQoSConfig::load() {
|
||||
if tuning.stop_irq_balance {
|
||||
offloads::stop_irq_balance().await;
|
||||
}
|
||||
offloads::netdev_budget(tuning.netdev_budget_usecs, tuning.netdev_budget_packets).await;
|
||||
offloads::ethtool_tweaks(&config.internet_interface, tuning).await;
|
||||
offloads::ethtool_tweaks(&config.isp_interface, tuning).await;
|
||||
}
|
||||
QUEUE_MONITOR_INTERVAL.store(*interval, std::sync::atomic::Ordering::Relaxed);
|
||||
lqos_bus::BusResponse::Ack
|
||||
}
|
||||
#[cfg(feature = "equinix_tests")]
|
||||
BusRequest::RequestLqosEquinixTest => {
|
||||
lqos_daht_test::lqos_daht_test().await
|
||||
|
@ -5,7 +5,7 @@ use lqos_config::LibreQoSConfig;
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
time::{Duration, Instant},
|
||||
time::{Duration, Instant}, sync::atomic::AtomicU64,
|
||||
};
|
||||
use tokio::{join, task, time};
|
||||
mod queue_reader;
|
||||
@ -154,11 +154,17 @@ async fn track_queues() {
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub(crate) static ref QUEUE_MONITOR_INTERVAL: AtomicU64 = AtomicU64::new(1000);
|
||||
}
|
||||
|
||||
pub async fn spawn_queue_monitor() {
|
||||
let _ = task::spawn(async {
|
||||
let queue_check_period_ms = lqos_config::EtcLqos::load().unwrap().queue_check_period_ms;
|
||||
let mut interval = time::interval(Duration::from_millis(queue_check_period_ms));
|
||||
QUEUE_MONITOR_INTERVAL.store(lqos_config::EtcLqos::load().unwrap().queue_check_period_ms, std::sync::atomic::Ordering::Relaxed);
|
||||
loop {
|
||||
let queue_check_period_ms = QUEUE_MONITOR_INTERVAL.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let mut interval = time::interval(Duration::from_millis(queue_check_period_ms));
|
||||
|
||||
let now = Instant::now();
|
||||
let _ = track_queues().await;
|
||||
let elapsed = now.elapsed();
|
||||
|
Loading…
Reference in New Issue
Block a user