Skip to content

Commit 0fe7070

Browse files
author
Joe Kurokawa
committed
Implement per interface IMDS
For requesting IMDS, ec2-net-utils only makes calls through the primray ENI which can lead to throttling by IMDS. We split these calls over the secondary ENIs in order to avoid making too many requests throught the primary interface. If setup_interface cannot use its own interface to call IMDS, use the current primary route, failing to do that use the lowest available secondary.
1 parent 293278c commit 0fe7070

File tree

2 files changed

+73
-15
lines changed

2 files changed

+73
-15
lines changed

debian/patches/update-networkd-priorities.patch

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
From 2761694987b588be2f6cc63e704a421e8a088b81 Mon Sep 17 00:00:00 2001
1+
From 5e1071bec2f025a9a90be250239eca5ef1dedb66 Mon Sep 17 00:00:00 2001
22
From: Joe Kurokawa <[email protected]>
3-
Date: Tue, 6 May 2025 21:31:36 +0000
3+
Date: Thu, 8 May 2025 00:00:55 +0000
44
Subject: [PATCH] change the priority of the networkd configs
55

66
ensure they're order before netplan
@@ -25,10 +25,10 @@ index a79fd09..9cb623b 100755
2525
;;
2626
stop|cleanup)
2727
diff --git a/lib/lib.sh b/lib/lib.sh
28-
index 981f643..858dc86 100644
28+
index 90cad29..936e986 100644
2929
--- a/lib/lib.sh
3030
+++ b/lib/lib.sh
31-
@@ -149,7 +149,7 @@ create_ipv4_aliases() {
31+
@@ -206,7 +206,7 @@ create_ipv4_aliases() {
3232
info "No addresses found for ${iface}"
3333
return 0
3434
fi
@@ -37,7 +37,7 @@ index 981f643..858dc86 100644
3737
mkdir -p "$drop_in_dir"
3838
local file="$drop_in_dir/ec2net_alias.conf"
3939
local work="${file}.new"
40-
@@ -208,7 +208,7 @@ create_rules() {
40+
@@ -265,7 +265,7 @@ create_rules() {
4141
local family=$4
4242
local addrs prefixes
4343
local local_addr_key subnet_pd_key
@@ -46,7 +46,7 @@ index 981f643..858dc86 100644
4646
mkdir -p "$drop_in_dir"
4747

4848
local -i ruleid=$((device_number+rule_base+100*network_card))
49-
@@ -376,7 +376,7 @@ create_interface_config() {
49+
@@ -433,7 +433,7 @@ create_interface_config() {
5050

5151
local -i retval=0
5252

lib/lib.sh

+67-9
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,84 @@ declare -r imds_token_path="api/token"
2424
declare -r syslog_facility="user"
2525
declare -r syslog_tag="ec2net"
2626
declare -i -r rule_base=10000
27+
declare -r primary_route="PRIMARY"
2728

2829
# Systemd installs routes with a metric of 1024 by default. We
2930
# override to a lower metric to ensure that our fully configured
3031
# interfaces are preferred over those in the process of being
3132
# configured.
3233
declare -i -r metric_base=512
33-
declare imds_endpoint imds_token
34+
declare imds_endpoint=""
35+
declare imds_token=""
36+
declare imds_interface=""
37+
declare self_iface_name=""
38+
39+
make_token_request() {
40+
local ep=${1:-""}
41+
local interface=${2:-""}
42+
local -a curl_opts=(--max-time 5 --connect-timeout 0.15 -s --fail -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 60")
43+
if [ -n "$interface" ]; then
44+
curl_opts+=(--interface "$interface")
45+
fi
46+
curl "${curl_opts[@]}" "${ep}/${imds_token_path}"
47+
}
48+
49+
get_lowest_secondary_interface() {
50+
# This is the best effort guess at what the lowest secondary interface would be.
51+
# It will return empty if there are no secondary interfaces.
52+
local iface
53+
local -a interfaces=()
54+
55+
for iface in /sys/class/net/*; do
56+
iface=${iface##*/}
57+
[[ $iface =~ ^(lo|docker|veth|dummy|vlan) ]] && continue
58+
interfaces+=("$iface")
59+
done
60+
printf "%s\n" "${interfaces[@]}" | sort -V | sed -n '2p'
61+
}
3462

3563
get_token() {
36-
# try getting a token early, using each endpoint in
37-
# turn. Whichever endpoint responds will be used for the rest of
38-
# the IMDS API calls. On initial interface setup, we'll retry
64+
# Try getting a token early, using each endpoint in
65+
# turn. Whichever interface and endpoint responds will be used for all the IMDS calls
66+
# used to setup the interface. For IMDS interface we will
67+
# try to call the IMDS from its self first, failing that the
68+
# primary eni, and failing that the best guess at the
69+
# lowest secondary eni if available.
70+
# On initial interface setup, we'll retry
3971
# this operation for up to 30 seconds, but on subsequent
4072
# invocations we avoid retrying
4173
local deadline
74+
local intf=$self_iface_name
4275
deadline=$(date -d "now+30 seconds" +%s)
4376
local old_opts=$-
77+
4478
while [ "$(date +%s)" -lt $deadline ]; do
4579
for ep in "${imds_endpoints[@]}"; do
4680
set +e
47-
imds_token=$(curl --max-time 5 --connect-timeout 0.15 -s --fail \
48-
-X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 60" ${ep}/${imds_token_path})
81+
imds_token=$(make_token_request "$ep" "$intf")
82+
83+
if [ -z "$imds_token" ]; then
84+
imds_token=$(make_token_request "$ep")
85+
intf="$primary_route"
86+
fi
87+
88+
if [ -z "$imds_token" ]; then
89+
lowest_secondary=$(get_lowest_secondary_interface)
90+
if [ -n "$lowest_secondary" ]; then
91+
imds_token=$(make_token_request "$ep" "$intf")
92+
intf="$lowest_secondary"
93+
fi
94+
fi
4995
[[ $old_opts = *e* ]] && set -e
96+
5097
if [ -n "$imds_token" ]; then
51-
debug "Got IMDSv2 token from ${ep}"
98+
debug "Got IMDSv2 token from ${ep} via ${intf}"
5299
imds_endpoint=$ep
100+
imds_interface=$intf
53101
return
54102
fi
55103
done
104+
56105
if [ ! -v EC2_IF_INITIAL_SETUP ]; then
57106
break
58107
fi
@@ -85,11 +134,19 @@ get_meta() {
85134
debug "[get_meta] Querying IMDS for ${key}"
86135

87136
get_token
88-
137+
if [[ -z $imds_endpoint || -z $imds_token || -z $imds_interface ]]; then
138+
error "[get_meta] Unable to obtain IMDS token, endpoint, or interface"
139+
return 1
140+
fi
89141
local url="${imds_endpoint}/meta-data/${key}"
90142
local meta rc
143+
local curl_opts=(-s --max-time 5 -H "X-aws-ec2-metadata-token:${imds_token}" -f)
144+
if [[ "$imds_interface" != "$primary_route" ]]; then
145+
curl_opts+=(--interface "$imds_interface")
146+
fi
147+
91148
while [ $attempts -lt $max_tries ]; do
92-
meta=$(curl -s --max-time 5 -H "X-aws-ec2-metadata-token:${imds_token}" -f "$url")
149+
meta=$(curl "${curl_opts[@]}" "$url")
93150
rc=$?
94151
if [ $rc -eq 0 ]; then
95152
echo "$meta"
@@ -472,6 +529,7 @@ setup_interface() {
472529
local -i device_number network_card rc
473530
iface=$1
474531
ether=$2
532+
self_iface_name=$1
475533

476534
network_card=$(_get_network_card "$iface" "$ether")
477535
device_number=$(_get_device_number "$iface" "$ether" "$network_card")

0 commit comments

Comments
 (0)