@@ -18,6 +18,7 @@ declare ether
1818declare unitdir
1919declare lockdir
2020declare reload_flag
21+ declare runtimeroot
2122
2223# Version information - substituted during installation
2324declare PACKAGE_VERSION=" AMAZON_EC2_NET_UTILS_VERSION"
@@ -140,7 +141,9 @@ get_meta() {
140141 local key=$1
141142 local max_tries=${2:- 10}
142143 declare -i attempts=0
143- [ -v EC2_IF_INITIAL_SETUP ] && debug " [get_meta] Querying IMDS for ${key} "
144+ if [ -v EC2_IF_INITIAL_SETUP ]; then
145+ debug " [get_meta] Querying IMDS for ${key} "
146+ fi
144147
145148 if [[ -z $imds_endpoint || -z $imds_token || -z $imds_interface ]]; then
146149 error " [get_meta] Unable to obtain IMDS token, endpoint, or interface"
@@ -532,6 +535,16 @@ _get_device_number() {
532535# NOTE: On many instance types, this value is not defined. This
533536# function will print the empty string on those instances. On
534537# instances where it is defined, it will be a numeric value.
538+ #
539+ # The value, like device-number, may not have propagated to IMDS
540+ # when a hot-plugged interface first appears. We can't tell
541+ # "undefined for this instance type" from "not yet propagated" from
542+ # a single query, so we retry on empty. Once the first ENI on this
543+ # boot has exhausted the retry loop with no value, we touch a marker
544+ # so subsequent ENIs skip the retry entirely. Without
545+ # this retry we can silently substitute 0 for a real network-card
546+ # index on multi-card instances, colliding route metrics and
547+ # routing-table IDs across interfaces.
535548_get_network_card () {
536549 local iface ether network_card
537550 iface=" $1 "
@@ -540,8 +553,26 @@ _get_network_card() {
540553 if _is_primary_interface " $ether " ; then
541554 echo 0 ; return 0
542555 fi
543- network_card=$( get_iface_imds " $ether " network-card)
556+
557+ local marker=" ${runtimeroot} /.no-network-card"
558+ if [ -e " $marker " ]; then
559+ echo ${network_card}
560+ return 0
561+ fi
562+
563+ local -i maxtries=40 ntries=0
564+ for (( ntries = 0 ; ntries < maxtries; ntries++ )) ; do
565+ network_card=$( get_iface_imds " $ether " network-card 1)
566+ if [ -n " $network_card " ]; then
567+ echo " $network_card "
568+ return 0
569+ fi
570+ sleep 0.1
571+ done
572+
573+ touch " $marker "
544574 echo ${network_card}
575+ return 0
545576}
546577
547578
@@ -617,7 +648,9 @@ maybe_reload_networkd() {
617648 networkctl reload
618649 debug " Reloaded networkd"
619650 else
620- [ -v EC2_IF_INITIAL_SETUP ] && debug " No networkd reload needed"
651+ if [ -v EC2_IF_INITIAL_SETUP ]; then
652+ debug " No networkd reload needed"
653+ fi
621654 fi
622655 else
623656 debug " Deferring networkd reload to another process"
@@ -627,18 +660,30 @@ maybe_reload_networkd() {
627660
628661register_networkd_reloader () {
629662 local -i registered=1 cnt=0
630- local -i max=10000
663+ local -i max=3000 # 300s (3000 × 0.1s); matches sysfs wait timeout in setup-policy-routes.sh
631664 local -r lockfile=" ${lockdir} /${iface} "
632665 local old_opts=$-
633666
667+ # If the existing lock owner is no longer alive, remove the stale lockfile
668+ # so subsequent invocations don't spin for up to 1000 seconds waiting on a
669+ # process that will never release it.
670+ if [ -f " ${lockfile} " ]; then
671+ local existing_pid
672+ existing_pid=$( cat " ${lockfile} " 2> /dev/null)
673+ if [ -n " $existing_pid " ] && ! kill -0 " $existing_pid " 2> /dev/null; then
674+ debug " Removing stale lock from dead process $existing_pid for ${iface} "
675+ rm -f " ${lockfile} "
676+ fi
677+ fi
678+
634679 # Disable -o errexit in the following block so we can capture
635680 # nonzero exit codes from a redirect without considering them
636681 # fatal errors
637682 set +e
638683 while [ $cnt -lt $max ]; do
639684 cnt+=1
640685 mkdir -p " $lockdir "
641- trap ' [ -v EC2_IF_INITIAL_SETUP ] && debug "Called trap" ; maybe_reload_networkd' EXIT
686+ trap ' if [ -v EC2_IF_INITIAL_SETUP ]; then debug "Called trap"; fi ; maybe_reload_networkd' EXIT
642687 # If the redirect fails, most likely because the target file
643688 # already exists and -o noclobber is in effect, $? will be set
644689 # nonzero. If it succeeds, it is set to 0
0 commit comments