Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions lib/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,27 @@ _install_and_reload() {
fi
}

_get_active_dropin_dir() {
local iface=$1
local default_dir="${unitdir}/70-${iface}.network.d"
local ifindex network_file
ifindex=$(cat "/sys/class/net/${iface}/ifindex" 2> /dev/null) || { echo "$default_dir"; return; }
network_file=$(sed -n 's/^NETWORK_FILE=//p' "/run/systemd/netif/links/${ifindex}" 2> /dev/null) || { echo "$default_dir"; return; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be a race condition between netplan and ec2-net-utils during a restart where netplan config is not first and you have two seperate configs since netplan has not logic to append to ec2-net-utils config?

Copy link
Copy Markdown
Contributor Author

@mjnowen mjnowen Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The policy-routes@.service start path calls systemd-networkd-wait-online -i $iface before _get_active_dropin_dir() is ever invoked, so networkd has already selected its active .network file (including any netplan-generated one) by that time. The refresh path (timer-driven) does not call wait-online explicitly, but the timer only fires 30s+ after the start path completes (OnActiveSec=30, OnUnitInactiveSec=60), so the interface is already fully online and NETWORK_FILE= is populated.

On Ubuntu, netplan's systemd generator runs during the early generator phase — before any services start — so 10-netplan-*.network files are on disk well before systemd-networkd.service begins matching interfaces to files.

On Amazon Linux 2023 there is no competing generator — 70-<iface>.network is the only (and therefore active) file, so the helper returns the same path as the old hardcoded logic and no race is possible.

On RHEL the default network manager is NetworkManager rather than systemd-networkd, so this codepath does not apply.

If detection somehow fails (e.g. a truly degenerate early-boot ordering), the helper falls back to 70-<iface>.network.d — the same path used before this change — so the worst case is parity with the current behaviour, not a new failure mode.

The coexistence of 70-<iface>.network alongside a lower-numbered netplan file is pre-existing and unchanged by this PR; it's precisely that coexistence that causes the bug this fix addresses.

if [ -n "$network_file" ]; then
echo "${network_file}.d"
else
echo "$default_dir"
fi
}

create_ipv4_aliases() {
local iface=$1
local mac=$2
local addresses
subnet_supports_ipv4 "$iface" || return 0
addresses=$(get_iface_imds $mac local-ipv4s | tail -n +2 | sort)
local drop_in_dir="${unitdir}/70-${iface}.network.d"
local drop_in_dir
drop_in_dir=$(_get_active_dropin_dir "$iface")
mkdir -p "$drop_in_dir"
local file="$drop_in_dir/ec2net_alias.conf"
local work="${file}.new"
Expand Down Expand Up @@ -295,7 +309,8 @@ create_rules() {
local family=$4
local addrs prefixes
local local_addr_key subnet_pd_key
local drop_in_dir="${unitdir}/70-${iface}.network.d"
local drop_in_dir
drop_in_dir=$(_get_active_dropin_dir "$iface")
mkdir -p "$drop_in_dir"

local -i ruleid=$((device_number+rule_base+100*network_card))
Expand Down