egress: refresh a leased pair on dhcp renewal and default anti-spoof to log
dnsmasq runs the dhcp-script on a renewal only with script-on-renewal, so a pair loaded at the first lease timed out while the lease kept renewing and the bridge table dropped the container's traffic. Set script-on-renewal, time pairs out remaining + 300s, default antiSpoof to log, and run the vm test through renewals with drop.
This commit is contained in:
parent
cf360b74b9
commit
5189e8fb4b
1 changed files with 107 additions and 39 deletions
|
|
@ -71,6 +71,10 @@ const POLL: Duration = Duration::from_millis(250);
|
|||
/// A lease timeout when dnsmasq names no remaining time.
|
||||
const DEFAULT_LEASE_SECS: u64 = 3600;
|
||||
|
||||
/// Seconds a leased pair outlives the lease it was loaded for. A renewal whose
|
||||
/// script run comes a little late then finds the pair still in the set.
|
||||
const LEASE_MARGIN_SECS: u64 = 300;
|
||||
|
||||
/// Where the bindings are kept between passes, when `HIVE_EGRESS_STATE` names
|
||||
/// no other file. It is on tmpfs: a reboot starts every port afresh.
|
||||
const STATE: &str = "/run/hive-egress-pins";
|
||||
|
|
@ -408,9 +412,10 @@ fn whois() -> Result<()> {
|
|||
/// The nft input for one lease event, or `None` for an event that changes
|
||||
/// nothing: `init`, an IPv6 address, an address or MAC that does not parse.
|
||||
///
|
||||
/// `add` and `old` replace the pair with one that times out after
|
||||
/// `remaining_secs`; `del` removes it. The first `add element` makes the
|
||||
/// `delete element` that follows succeed whether or not the pair was there.
|
||||
/// `add` and `old` replace the pair with one that times out `remaining_secs`
|
||||
/// plus [`LEASE_MARGIN_SECS`] from now, so every renewal moves the timeout
|
||||
/// forward; `del` removes it. The first `add element` makes the `delete
|
||||
/// element` that follows succeed whether or not the pair was there.
|
||||
pub(crate) fn lease_script(
|
||||
action: &str,
|
||||
mac: &str,
|
||||
|
|
@ -421,11 +426,12 @@ pub(crate) fn lease_script(
|
|||
let ip: std::net::Ipv4Addr = ip.parse().ok()?;
|
||||
let set = format!("{TABLE} lease_v4");
|
||||
let pair = format!("{mac} . {ip}");
|
||||
let timeout = remaining_secs.saturating_add(LEASE_MARGIN_SECS);
|
||||
match action {
|
||||
"add" | "old" => Some(format!(
|
||||
"add element {set} {{ {pair} }}\n\
|
||||
delete element {set} {{ {pair} }}\n\
|
||||
add element {set} {{ {pair} timeout {remaining_secs}s }}\n"
|
||||
add element {set} {{ {pair} timeout {timeout}s }}\n"
|
||||
)),
|
||||
"del" => Some(format!(
|
||||
"add element {set} {{ {pair} }}\ndelete element {set} {{ {pair} }}\n"
|
||||
|
|
@ -1033,7 +1039,7 @@ mod tests {
|
|||
let script = &calls[0];
|
||||
assert!(script.starts_with("table bridge hive_egress { }"));
|
||||
assert!(script.contains("port_mac { \"vb-a\" . 02:00:00:00:00:0a }"));
|
||||
assert!(script.contains("lease_v4 { 02:00:00:00:00:0a . 10.42.0.10 timeout 90s }"));
|
||||
assert!(script.contains("lease_v4 { 02:00:00:00:00:0a . 10.42.0.10 timeout 390s }"));
|
||||
assert!(!script.contains("flush set"), "the sets are new");
|
||||
}
|
||||
|
||||
|
|
@ -1239,7 +1245,7 @@ mod tests {
|
|||
#[test]
|
||||
fn lease_events_become_nft_input() {
|
||||
let add = lease_script("add", "02:00:00:00:00:0a", "10.42.0.10", 90).unwrap();
|
||||
assert!(add.ends_with("add element bridge hive_egress lease_v4 { 02:00:00:00:00:0a . 10.42.0.10 timeout 90s }\n"));
|
||||
assert!(add.ends_with("add element bridge hive_egress lease_v4 { 02:00:00:00:00:0a . 10.42.0.10 timeout 390s }\n"));
|
||||
assert!(add.contains("delete element"));
|
||||
assert_eq!(
|
||||
lease_script("old", "02:00:00:00:00:0a", "10.42.0.10", 90),
|
||||
|
|
@ -1258,6 +1264,27 @@ mod tests {
|
|||
assert_eq!(lease_script("add", "nonsense", "10.42.0.10", 90), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_renewal_moves_the_timeout_to_the_new_remaining_time_plus_the_margin() {
|
||||
let mac = "02:00:00:00:00:0a";
|
||||
let first = lease_script("add", mac, "10.42.0.10", 120).unwrap();
|
||||
let renewed = lease_script("old", mac, "10.42.0.10", 120).unwrap();
|
||||
let later = lease_script("old", mac, "10.42.0.10", 3600).unwrap();
|
||||
assert!(first.ends_with("10.42.0.10 timeout 420s }\n"));
|
||||
assert_eq!(renewed, first, "old and add load the same pair");
|
||||
assert!(later.ends_with("10.42.0.10 timeout 3900s }\n"));
|
||||
assert!(
|
||||
later.starts_with("add element bridge hive_egress lease_v4 { 02:00:00:00:00:0a . 10.42.0.10 }\ndelete element"),
|
||||
"the old timeout is deleted first, so the new one replaces it"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_remaining_time_that_overflows_with_the_margin_does_not_wrap() {
|
||||
let script = lease_script("old", "02:00:00:00:00:0a", "10.42.0.10", u64::MAX).unwrap();
|
||||
assert!(script.contains(&format!("timeout {}s", u64::MAX)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seeding_skips_expired_and_malformed_leases() {
|
||||
let leases = "2000 02:00:00:00:00:0a 10.42.0.10 a *\n\
|
||||
|
|
@ -1265,9 +1292,9 @@ mod tests {
|
|||
0 02:00:00:00:00:0c 10.42.0.12 c *\n\
|
||||
garbage\n";
|
||||
let script = seed_script(leases, 1000);
|
||||
assert!(script.contains("02:00:00:00:00:0a . 10.42.0.10 timeout 1000s"));
|
||||
assert!(script.contains("02:00:00:00:00:0a . 10.42.0.10 timeout 1300s"));
|
||||
assert!(!script.contains("10.42.0.11"));
|
||||
assert!(script.contains("10.42.0.12 timeout 3600s"));
|
||||
assert!(script.contains("10.42.0.12 timeout 3900s"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue