Implement correct signal handling for SIGINT, SIGTERM and SIGHUP

Extend the signals handler to reload configuration on SIGHUP, and terminate
on SIGINT and SIGTERM.

FIXES #202
This commit is contained in:
Herbert Wolverson
2023-01-16 15:07:20 +00:00
parent 05bb1ee959
commit 6f49b2498a
3 changed files with 92 additions and 59 deletions

View File

@@ -2,23 +2,23 @@ mod ip_mapping;
mod libreqos_tracker;
#[cfg(feature = "equinix_tests")]
mod lqos_daht_test;
mod offloads;
mod tuning;
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}, queue_tracker::QUEUE_MONITOR_INTERVAL};
use crate::{ip_mapping::{clear_ip_flows, del_ip_flow, list_mapped_ips, map_ip_to_flow}};
use anyhow::Result;
use log::{info, warn};
use lqos_bus::{
cookie_value, decode_request, encode_response, BusReply, BusRequest, BUS_BIND_ADDRESS,
};
use lqos_config::{EtcLqos, LibreQoSConfig};
use lqos_config::LibreQoSConfig;
use lqos_sys::LibreQoSKernels;
use signal_hook::{consts::SIGINT, iterator::Signals};
use signal_hook::{consts::{SIGINT, SIGHUP, SIGTERM }, iterator::Signals};
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
join,
net::{TcpListener, TcpStream},
net::{TcpListener, TcpStream}
};
#[tokio::main]
@@ -26,18 +26,7 @@ async fn main() -> Result<()> {
env_logger::init(); // Configure log level with RUST_LOG environment variable
info!("LibreQoS Daemon Starting");
let config = LibreQoSConfig::load()?;
let etc_lqos = EtcLqos::load()?;
// Disable offloading
if let Some(tuning) = &etc_lqos.tuning {
offloads::bpf_sysctls().await;
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;
}
tuning::tune_lqosd_from_config_file(&config)?;
// Start the XDP/TC kernels
let kernels = if config.on_a_stick_mode {
@@ -58,13 +47,34 @@ async fn main() -> Result<()> {
libreqos_tracker::spawn_queue_structure_monitor(),
);
let mut signals = Signals::new(&[SIGINT])?;
// Handle signals
let mut signals = Signals::new(&[SIGINT, SIGHUP, SIGTERM ])?;
std::thread::spawn(move || {
for sig in signals.forever() {
warn!("Received signal {:?}", sig);
std::mem::drop(kernels);
std::process::exit(0);
match sig {
SIGINT | SIGTERM => {
match sig {
SIGINT => warn!("Terminating on SIGINT"),
SIGTERM => warn!("Terminating on SIGTERM"),
_ => warn!("This should never happen - terminating on unknown signal"),
}
std::mem::drop(kernels);
std::process::exit(0);
}
SIGHUP => {
warn!("Reloading configuration because of SIGHUP");
if let Ok(config) = LibreQoSConfig::load() {
let result = tuning::tune_lqosd_from_config_file(&config);
match result {
Err(err) => { warn!("Unable to HUP tunables: {:?}", err) },
Ok(..) => {}
}
} else {
warn!("Unable to reload configuration");
}
}
_ => warn!("No handler for signal: {sig}"),
}
}
});
@@ -116,18 +126,8 @@ 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
BusRequest::UpdateLqosDTuning(..) => {
tuning::tune_lqosd_from_bus(&req).await
}
#[cfg(feature = "equinix_tests")]
BusRequest::RequestLqosEquinixTest => {

View File

@@ -0,0 +1,42 @@
mod offloads;
use anyhow::Result;
use lqos_bus::{BusRequest, BusResponse};
use lqos_config::{EtcLqos, LibreQoSConfig};
use crate::queue_tracker::QUEUE_MONITOR_INTERVAL;
pub fn tune_lqosd_from_config_file(config: &LibreQoSConfig) -> Result<()> {
let etc_lqos = EtcLqos::load()?;
// Disable offloading
if let Some(tuning) = &etc_lqos.tuning {
offloads::bpf_sysctls();
if tuning.stop_irq_balance {
offloads::stop_irq_balance();
}
offloads::netdev_budget(tuning.netdev_budget_usecs, tuning.netdev_budget_packets);
offloads::ethtool_tweaks(&config.internet_interface, tuning);
offloads::ethtool_tweaks(&config.isp_interface, tuning);
}
let interval = etc_lqos.queue_check_period_ms;
QUEUE_MONITOR_INTERVAL.store(interval, std::sync::atomic::Ordering::Relaxed);
Ok(())
}
pub async fn tune_lqosd_from_bus(request: &BusRequest) -> BusResponse {
match request {
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();
}
offloads::netdev_budget(tuning.netdev_budget_usecs, tuning.netdev_budget_packets);
offloads::ethtool_tweaks(&config.internet_interface, tuning);
offloads::ethtool_tweaks(&config.isp_interface, tuning);
}
QUEUE_MONITOR_INTERVAL.store(*interval, std::sync::atomic::Ordering::Relaxed);
lqos_bus::BusResponse::Ack
}
_ => BusResponse::Fail("That wasn't a tuning request".to_string())
}
}

View File

@@ -1,43 +1,38 @@
use lqos_config::Tunables;
use tokio::process::Command;
use std::process::Command;
pub async fn bpf_sysctls() {
pub fn bpf_sysctls() {
let _ = Command::new("/sbin/sysctl")
.arg(format!("net.core.bpf_jit_enable=1"))
.output()
.await;
.output();
}
pub async fn stop_irq_balance() {
pub fn stop_irq_balance() {
let _ = Command::new("/bin/systemctl")
.args(["stop", "irqbalance"])
.output()
.await;
.output();
}
pub async fn netdev_budget(usecs: u32, packets: u32) {
pub fn netdev_budget(usecs: u32, packets: u32) {
let _ = Command::new("/sbin/sysctl")
.arg(format!("net.core.netdev_budget_usecs={usecs}"))
.output()
.await;
.output();
let _ = Command::new("/sbin/sysctl")
.arg(format!("net.core.netdev_budget={packets}"))
.output()
.await;
.output();
}
async fn disable_individual_offload(interface: &str, feature: &str) {
fn disable_individual_offload(interface: &str, feature: &str) {
let _ = Command::new("/sbin/ethtool")
.args(["--offload", interface, feature, "off"])
.output()
.await;
.output();
}
pub async fn ethtool_tweaks(interface: &str, tuning: &Tunables) {
pub fn ethtool_tweaks(interface: &str, tuning: &Tunables) {
// Disabling individually to avoid complaints that a card doesn't support a feature anyway
for feature in tuning.disable_offload.iter() {
disable_individual_offload(interface, feature).await;
disable_individual_offload(interface, feature);
}
let _ = Command::new("/sbin/ethtool")
@@ -47,8 +42,7 @@ pub async fn ethtool_tweaks(interface: &str, tuning: &Tunables) {
"rx-usecs",
&format!("\"{}\"", tuning.rx_usecs),
])
.output()
.await;
.output();
let _ = Command::new("/sbin/ethtool")
.args([
@@ -57,20 +51,17 @@ pub async fn ethtool_tweaks(interface: &str, tuning: &Tunables) {
"tx-usecs",
&format!("\"{}\"", tuning.tx_usecs),
])
.output()
.await;
.output();
if tuning.disable_rxvlan {
let _ = Command::new("/sbin/ethtool")
.args(["-K", interface, "rxvlan", "off"])
.output()
.await;
.output();
}
if tuning.disable_txvlan {
let _ = Command::new("/sbin/ethtool")
.args(["-K", interface, "txvlan", "off"])
.output()
.await;
.output();
}
}