zlayer-overlay 0.13.0

Encrypted overlay networking for containers using boringtun userspace WireGuard
Documentation
//! Keep the host's network managers from touching overlay interfaces.
//!
//! `systemd-networkd` (and `NetworkManager`) with a permissive default match
//! will try to MANAGE a freshly-created overlay link (`zl-*`, `veth-*`) — bring it
//! up, run DHCP / IPv6 autoconf, and (observed on a CI runner) hit the
//! 3-minute systemd-networkd watchdog and `SIGABRT` while processing a `zl-*`
//! `Link UP`. overlayd configures these links itself via netlink, so we drop a
//! tiny "Unmanaged" config for each manager that is present.
//!
//! Best-effort + idempotent: a manager's drop-in is only written when that
//! manager's runtime dir exists, every error is logged (never fatal), and the
//! manager is reloaded so it re-evaluates already-created links. Root-mode only
//! (rootless overlay creates no host `zl-*` links — `pasta` handles egress);
//! a pure no-op on non-Linux.

#[cfg(target_os = "linux")]
mod imp {
    use std::path::Path;

    pub(super) const NETWORKD_DROPIN: &str = "/run/systemd/network/10-zlayer-unmanaged.network";
    pub(super) const NM_DROPIN: &str = "/run/NetworkManager/conf.d/10-zlayer-unmanaged.conf";

    /// systemd-networkd `.network` drop-in: match the overlay link name globs
    /// and mark them unmanaged so networkd never brings them up / runs the
    /// watchdog against them.
    pub(super) const NETWORKD_BODY: &str = "# Managed by ZLayer overlayd — do not edit.\n\
# Overlay links are configured by overlayd via netlink; keep systemd-networkd\n\
# from managing them (it otherwise hits its watchdog on a zl-* Link UP).\n\
[Match]\n\
Name=zl-* veth-*\n\
\n\
[Link]\n\
Unmanaged=yes\n";

    /// `NetworkManager` keyfile drop-in marking the same interface-name globs
    /// unmanaged.
    pub(super) const NM_BODY: &str = "# Managed by ZLayer overlayd — do not edit.\n\
[keyfile]\n\
unmanaged-devices=interface-name:zl-*;interface-name:veth-*\n";

    pub(super) fn mark() {
        // systemd-networkd: present whenever `/run/systemd` exists (systemd
        // host). Create the runtime config dir if needed, write, reload.
        if Path::new("/run/systemd").is_dir() {
            if let Err(e) = std::fs::create_dir_all("/run/systemd/network") {
                tracing::warn!(error = %e, "could not create /run/systemd/network for unmanaged drop-in");
            } else if let Err(e) = std::fs::write(NETWORKD_DROPIN, NETWORKD_BODY) {
                tracing::warn!(error = %e, path = NETWORKD_DROPIN, "failed to write systemd-networkd unmanaged drop-in");
            } else {
                let _ = std::process::Command::new("networkctl")
                    .arg("reload")
                    .status();
                tracing::info!(
                    path = NETWORKD_DROPIN,
                    "marked overlay interfaces Unmanaged for systemd-networkd"
                );
            }
        }
        // NetworkManager: only when it is actually running (`/run/NetworkManager`
        // exists). Create conf.d if missing, write, reload.
        if Path::new("/run/NetworkManager").is_dir() {
            if let Err(e) = std::fs::create_dir_all("/run/NetworkManager/conf.d") {
                tracing::warn!(error = %e, "could not create /run/NetworkManager/conf.d for unmanaged drop-in");
            } else if let Err(e) = std::fs::write(NM_DROPIN, NM_BODY) {
                tracing::warn!(error = %e, path = NM_DROPIN, "failed to write NetworkManager unmanaged drop-in");
            } else {
                let _ = std::process::Command::new("nmcli")
                    .args(["general", "reload"])
                    .status();
                tracing::info!(
                    path = NM_DROPIN,
                    "marked overlay interfaces unmanaged for NetworkManager"
                );
            }
        }
    }

    pub(super) fn unmark() {
        // Remove each drop-in if present and reload the manager. Idempotent:
        // a missing file is success.
        let mut reload_networkd = false;
        match std::fs::remove_file(NETWORKD_DROPIN) {
            Ok(()) => reload_networkd = true,
            Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
            Err(e) => {
                tracing::warn!(error = %e, path = NETWORKD_DROPIN, "failed to remove networkd unmanaged drop-in");
            }
        }
        if reload_networkd {
            let _ = std::process::Command::new("networkctl")
                .arg("reload")
                .status();
        }

        let mut reload_nm = false;
        match std::fs::remove_file(NM_DROPIN) {
            Ok(()) => reload_nm = true,
            Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
            Err(e) => {
                tracing::warn!(error = %e, path = NM_DROPIN, "failed to remove NetworkManager unmanaged drop-in");
            }
        }
        if reload_nm {
            let _ = std::process::Command::new("nmcli")
                .args(["general", "reload"])
                .status();
        }
    }
}

/// Install drop-ins telling `systemd-networkd` and `NetworkManager` to leave
/// `zl-*` / `veth-*` overlay interfaces unmanaged. Best-effort, idempotent,
/// root-mode only. No-op on non-Linux.
pub fn mark_overlay_interfaces_unmanaged() {
    #[cfg(target_os = "linux")]
    imp::mark();
}

/// Remove the unmanaged drop-ins (clean reversion on overlay teardown).
/// Best-effort, idempotent. No-op on non-Linux.
pub fn unmark_overlay_interfaces_unmanaged() {
    #[cfg(target_os = "linux")]
    imp::unmark();
}

#[cfg(all(test, target_os = "linux"))]
mod tests {
    use super::imp::{NETWORKD_BODY, NM_BODY};

    #[test]
    fn networkd_dropin_marks_overlay_links_unmanaged() {
        assert!(NETWORKD_BODY.contains("[Match]"));
        assert!(
            NETWORKD_BODY.contains("Name=zl-* veth-*"),
            "must match both zl-* and veth-* overlay links"
        );
        assert!(NETWORKD_BODY.contains("[Link]"));
        assert!(
            NETWORKD_BODY.contains("Unmanaged=yes"),
            "must mark the matched links Unmanaged"
        );
    }

    #[test]
    fn networkmanager_dropin_marks_overlay_links_unmanaged() {
        assert!(NM_BODY.contains("[keyfile]"));
        assert!(
            NM_BODY.contains("unmanaged-devices=interface-name:zl-*;interface-name:veth-*"),
            "must mark zl-* and veth-* unmanaged for NetworkManager"
        );
    }
}