@@ -447,6 +447,12 @@ fn run_daemon(config: config::Config, reload_source: Option<String>) -> Result<(
447447 } else {
448448 0
449449 } ;
450+ // Periodic network refresh: re-resolve bind_ip and dst_mac every 60 s.
451+ // Catches IP changes from DHCP renewal / PPPoE reconnect / cloud reassignment
452+ // that would otherwise leave a stale partial_ip_csum in the BPF config map
453+ // and silently black-hole all outgoing traffic until the next SIGHUP.
454+ let mut net_refresh_tick: u32 = 0 ;
455+ const NET_REFRESH_TICKS : u32 = 120 ; // 120 × 500 ms = 60 s
450456
451457 loop {
452458 std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) ;
@@ -473,6 +479,25 @@ fn run_daemon(config: config::Config, reload_source: Option<String>) -> Result<(
473479 }
474480 }
475481
482+ // Periodic network refresh: re-resolve bind_ip, partial_ip_csum and dst_mac.
483+ // Re-uses build_gut_config which does a fast ARP-cache lookup first;
484+ // the slow path (ARP probes) only fires when the cache is empty.
485+ net_refresh_tick += 1 ;
486+ if net_refresh_tick >= NET_REFRESH_TICKS {
487+ net_refresh_tick = 0 ;
488+ for mgr in & mut managers {
489+ if let Some ( peer) = config. peers . iter ( ) . find ( |p| p. name == mgr. interface ( ) ) {
490+ let single = make_single ( & config, peer) ;
491+ if let Err ( e) = mgr. update_config ( & single) {
492+ eprintln ! (
493+ "Periodic network refresh failed for '{}': {e}" ,
494+ mgr. interface( )
495+ ) ;
496+ }
497+ }
498+ }
499+ }
500+
476501 if reload:: should_reload ( ) {
477502 reload:: clear_reload_flag ( ) ;
478503 sd_notify ( "RELOADING=1" ) ;
0 commit comments