mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2024-11-21 15:57:24 -06:00
ISSUE #518 : Remove the "hot cache clear" call altogether, and instead use a timeout/expiration to clear the cache gracefully. This allowed the map to be unpinned, and never accessed from userspace. Should fix the reload delays, and still give accurate mappings after a complete map rebuild.
This commit is contained in:
parent
1e586e4335
commit
7d53421b92
@ -986,7 +986,6 @@ def refreshShapers():
|
|||||||
print("Executing XDP-CPUMAP-TC IP filter commands")
|
print("Executing XDP-CPUMAP-TC IP filter commands")
|
||||||
numXdpCommands = ipMapBatch.length()
|
numXdpCommands = ipMapBatch.length()
|
||||||
if enable_actual_shell_commands():
|
if enable_actual_shell_commands():
|
||||||
ipMapBatch.finish_ip_mappings()
|
|
||||||
ipMapBatch.submit()
|
ipMapBatch.submit()
|
||||||
#for command in xdpCPUmapCommands:
|
#for command in xdpCPUmapCommands:
|
||||||
# logging.info(command)
|
# logging.info(command)
|
||||||
|
@ -70,11 +70,6 @@ pub enum BusRequest {
|
|||||||
upload: bool,
|
upload: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// After a batch of `MapIpToFlow` requests, this command will
|
|
||||||
/// clear the hot cache, forcing the XDP program to re-read the
|
|
||||||
/// mapping table.
|
|
||||||
ClearHotCache,
|
|
||||||
|
|
||||||
/// Requests that the XDP program unmap an IP address/subnet from
|
/// Requests that the XDP program unmap an IP address/subnet from
|
||||||
/// the traffic management system.
|
/// the traffic management system.
|
||||||
DelIpFlow {
|
DelIpFlow {
|
||||||
|
@ -234,12 +234,6 @@ impl BatchedCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish_ip_mappings(&mut self) -> PyResult<()> {
|
|
||||||
let request = BusRequest::ClearHotCache;
|
|
||||||
self.batch.push(request);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn length(&self) -> PyResult<usize> {
|
pub fn length(&self) -> PyResult<usize> {
|
||||||
Ok(self.batch.len())
|
Ok(self.batch.len())
|
||||||
}
|
}
|
||||||
|
@ -31,12 +31,19 @@ struct ip_hash_key {
|
|||||||
#define USE_HOTCACHE 1
|
#define USE_HOTCACHE 1
|
||||||
|
|
||||||
#ifdef USE_HOTCACHE
|
#ifdef USE_HOTCACHE
|
||||||
|
|
||||||
|
#define HOT_CACHE_EXPIRY 1000000000 // 1 second
|
||||||
|
|
||||||
|
struct hot_cache_data {
|
||||||
|
__u64 expires;
|
||||||
|
struct ip_hash_info info;
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
||||||
__uint(max_entries, HOT_CACHE_SIZE);
|
__uint(max_entries, HOT_CACHE_SIZE);
|
||||||
__type(key, struct in6_addr);
|
__type(key, struct in6_addr);
|
||||||
__type(value, struct ip_hash_info);
|
__type(value, struct hot_cache_data);
|
||||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
|
||||||
} ip_to_cpu_and_tc_hotcache SEC(".maps");
|
} ip_to_cpu_and_tc_hotcache SEC(".maps");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -45,7 +52,7 @@ struct {
|
|||||||
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
|
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
|
||||||
__uint(max_entries, IP_HASH_ENTRIES_MAX);
|
__uint(max_entries, IP_HASH_ENTRIES_MAX);
|
||||||
__type(key, struct ip_hash_key);
|
__type(key, struct ip_hash_key);
|
||||||
__type(value, struct ip_hash_info);
|
__type(value, struct hot_cache_data);
|
||||||
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
__uint(pinning, LIBBPF_PIN_BY_NAME);
|
||||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||||
} map_ip_to_cpu_and_tc SEC(".maps");
|
} map_ip_to_cpu_and_tc SEC(".maps");
|
||||||
@ -94,18 +101,19 @@ static __always_inline struct ip_hash_info * setup_lookup_key_and_tc_cpu(
|
|||||||
|
|
||||||
#ifdef USE_HOTCACHE
|
#ifdef USE_HOTCACHE
|
||||||
// Try a hot cache search
|
// Try a hot cache search
|
||||||
ip_info = bpf_map_lookup_elem(
|
struct hot_cache_data * cached;
|
||||||
|
cached = bpf_map_lookup_elem(
|
||||||
&ip_to_cpu_and_tc_hotcache,
|
&ip_to_cpu_and_tc_hotcache,
|
||||||
&lookup_key->address
|
&lookup_key->address
|
||||||
);
|
);
|
||||||
if (ip_info) {
|
if (cached && cached->expires < dissector->now) {
|
||||||
// Is it a negative hit?
|
// Is it a negative hit?
|
||||||
if (ip_info->cpu == NEGATIVE_HIT) {
|
if (cached->info.cpu == NEGATIVE_HIT) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We got a cache hit, so return
|
// We got a cache hit, so return
|
||||||
return ip_info;
|
return &cached->info;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -116,11 +124,15 @@ static __always_inline struct ip_hash_info * setup_lookup_key_and_tc_cpu(
|
|||||||
);
|
);
|
||||||
#ifdef USE_HOTCACHE
|
#ifdef USE_HOTCACHE
|
||||||
if (ip_info) {
|
if (ip_info) {
|
||||||
|
struct hot_cache_data hot_data = {
|
||||||
|
.expires = dissector->now + HOT_CACHE_EXPIRY,
|
||||||
|
.info = *ip_info
|
||||||
|
};
|
||||||
// We found it, so add it to the cache
|
// We found it, so add it to the cache
|
||||||
bpf_map_update_elem(
|
bpf_map_update_elem(
|
||||||
&ip_to_cpu_and_tc_hotcache,
|
&ip_to_cpu_and_tc_hotcache,
|
||||||
&lookup_key->address,
|
&lookup_key->address,
|
||||||
ip_info,
|
&hot_data,
|
||||||
BPF_NOEXIST
|
BPF_NOEXIST
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -58,7 +58,6 @@ pub fn del_ip_from_tc(address: &str, upload: bool) -> Result<()> {
|
|||||||
let ip = XdpIpAddress::from_ip(ip);
|
let ip = XdpIpAddress::from_ip(ip);
|
||||||
let mut key = IpHashKey { prefixlen: ip_to_add.prefix, address: ip.0 };
|
let mut key = IpHashKey { prefixlen: ip_to_add.prefix, address: ip.0 };
|
||||||
bpf_map.delete(&mut key)?;
|
bpf_map.delete(&mut key)?;
|
||||||
clear_hot_cache()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +73,6 @@ pub fn clear_ips_from_tc() -> Result<()> {
|
|||||||
)?;
|
)?;
|
||||||
bpf_map.clear()?;
|
bpf_map.clear()?;
|
||||||
|
|
||||||
clear_hot_cache()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,12 +91,3 @@ pub fn list_mapped_ips() -> Result<Vec<(IpHashKey, IpHashData)>> {
|
|||||||
|
|
||||||
Ok(raw)
|
Ok(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clears the "hot cache", which should be done whenever you change the IP
|
|
||||||
/// mappings - because otherwise cached data will keep going to the previous
|
|
||||||
/// destinations.
|
|
||||||
pub fn clear_hot_cache() -> Result<()> {
|
|
||||||
let mut bpf_map = BpfMap::<XdpIpAddress, IpHashData>::from_path("/sys/fs/bpf/ip_to_cpu_and_tc_hotcache")?;
|
|
||||||
bpf_map.clear()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -23,7 +23,7 @@ mod bpf_iterator;
|
|||||||
pub mod flowbee_data;
|
pub mod flowbee_data;
|
||||||
|
|
||||||
pub use ip_mapping::{
|
pub use ip_mapping::{
|
||||||
add_ip_to_tc, clear_ips_from_tc, del_ip_from_tc, list_mapped_ips, clear_hot_cache,
|
add_ip_to_tc, clear_ips_from_tc, del_ip_from_tc, list_mapped_ips,
|
||||||
};
|
};
|
||||||
pub use kernel_wrapper::LibreQoSKernels;
|
pub use kernel_wrapper::LibreQoSKernels;
|
||||||
pub use linux::num_possible_cpus;
|
pub use linux::num_possible_cpus;
|
||||||
|
@ -19,10 +19,6 @@ pub(crate) fn map_ip_to_flow(
|
|||||||
expect_ack(lqos_sys::add_ip_to_tc(ip_address, *tc_handle, cpu, upload))
|
expect_ack(lqos_sys::add_ip_to_tc(ip_address, *tc_handle, cpu, upload))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clear_hot_cache() -> BusResponse {
|
|
||||||
expect_ack(lqos_sys::clear_hot_cache())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn del_ip_flow(ip_address: &str, upload: bool) -> BusResponse {
|
pub(crate) fn del_ip_flow(ip_address: &str, upload: bool) -> BusResponse {
|
||||||
expect_ack(lqos_sys::del_ip_from_tc(ip_address, upload))
|
expect_ack(lqos_sys::del_ip_from_tc(ip_address, upload))
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ mod node_manager;
|
|||||||
// Use JemAllocator only on supported platforms
|
// Use JemAllocator only on supported platforms
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
use jemallocator::Jemalloc;
|
use jemallocator::Jemalloc;
|
||||||
use crate::ip_mapping::clear_hot_cache;
|
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
@ -177,7 +176,6 @@ fn handle_bus_requests(
|
|||||||
BusRequest::MapIpToFlow { ip_address, tc_handle, cpu, upload } => {
|
BusRequest::MapIpToFlow { ip_address, tc_handle, cpu, upload } => {
|
||||||
map_ip_to_flow(ip_address, tc_handle, *cpu, *upload)
|
map_ip_to_flow(ip_address, tc_handle, *cpu, *upload)
|
||||||
}
|
}
|
||||||
BusRequest::ClearHotCache => clear_hot_cache(),
|
|
||||||
BusRequest::DelIpFlow { ip_address, upload } => {
|
BusRequest::DelIpFlow { ip_address, upload } => {
|
||||||
del_ip_flow(ip_address, *upload)
|
del_ip_flow(ip_address, *upload)
|
||||||
}
|
}
|
||||||
|
@ -44,8 +44,6 @@ enum Commands {
|
|||||||
Clear,
|
Clear,
|
||||||
/// List all mapped IPs.
|
/// List all mapped IPs.
|
||||||
List,
|
List,
|
||||||
/// Flushes the Hot Cache (to be used after when you are done making changes).
|
|
||||||
Flush,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn talk_to_server(command: BusRequest) -> Result<()> {
|
async fn talk_to_server(command: BusRequest) -> Result<()> {
|
||||||
@ -124,7 +122,6 @@ pub async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
Some(Commands::Clear) => talk_to_server(BusRequest::ClearIpFlow).await?,
|
Some(Commands::Clear) => talk_to_server(BusRequest::ClearIpFlow).await?,
|
||||||
Some(Commands::List) => talk_to_server(BusRequest::ListIpFlow).await?,
|
Some(Commands::List) => talk_to_server(BusRequest::ListIpFlow).await?,
|
||||||
Some(Commands::Flush) => talk_to_server(BusRequest::ClearHotCache).await?,
|
|
||||||
None => {
|
None => {
|
||||||
println!("Run with --help to see instructions");
|
println!("Run with --help to see instructions");
|
||||||
exit(0);
|
exit(0);
|
||||||
|
Loading…
Reference in New Issue
Block a user