]>
Commit | Line | Data |
---|---|---|
2f03d69f HR |
1 | #!/bin/sh |
2 | # | |
3 | # Supported formats: | |
e405501e AAF |
4 | # rd.nvmf.hostnqn=<hostnqn> |
5 | # rd.nvmf.hostid=<hostid> | |
6 | # rd.nvmf.discover=<transport>,<traddr>,<host-traddr>,<trsvcid> | |
2f03d69f HR |
7 | # |
8 | # Examples: | |
e405501e AAF |
9 | # rd.nvmf.hostnqn=nqn.2014-08.org.nvmexpress:uuid:37303738-3034-584d-5137-333230423843 |
10 | # rd.nvmf.discover=rdma,192.168.1.3,,4420 | |
11 | # rd.nvmf.discover=tcp,192.168.1.3,,4420 | |
12 | # rd.nvmf.discover=tcp,192.168.1.3 | |
13 | # rd.nvmf.discover=fc,nn-0x200400a098d85236:pn-0x201400a098d85236,nn-0x200000109b7db455:pn-0x100000109b7db455 | |
14 | # rd.nvmf.discover=fc,auto | |
2f03d69f HR |
15 | # |
16 | # Note: FC does autodiscovery, so typically there is no need to | |
17 | # specify any discover parameters for FC. | |
18 | # | |
19 | ||
b490f6f7 MW |
20 | command -v getarg > /dev/null || . /lib/dracut-lib.sh |
21 | command -v is_ip > /dev/null || . /lib/net-lib.sh | |
22 | ||
23 | ## Sample NBFT output from nvme show-nbft -H -s -d -o json | |
24 | # [ | |
25 | # { | |
26 | # "filename":"/sys/firmware/acpi/tables/NBFT", | |
27 | # "host":{ | |
28 | # "nqn":"nqn.2014-08.org.nvmexpress:uuid:d6f07002-7eb5-4841-a185-400e296afae4", | |
29 | # "id":"111919da-21ea-cc4e-bafe-216d8372dd31", | |
30 | # "host_id_configured":0, | |
31 | # "host_nqn_configured":0, | |
32 | # "primary_admin_host_flag":"not indicated" | |
33 | # }, | |
34 | # "subsystem":[ | |
35 | # { | |
36 | # "index":1, | |
37 | # "num_hfis":1, | |
38 | # "hfis":[ | |
39 | # 1 | |
40 | # ], | |
41 | # "transport":"tcp", | |
42 | # "transport_address":"192.168.100.216", | |
43 | # "transport_svcid":"4420", | |
44 | # "subsys_port_id":0, | |
45 | # "nsid":1, | |
46 | # "nid_type":"uuid", | |
47 | # "nid":"424d1c8a-8ef9-4681-b2fc-8c343bd8fa69", | |
48 | # "subsys_nqn":"timberland-01", | |
49 | # "controller_id":0, | |
50 | # "asqsz":0, | |
51 | # "pdu_header_digest_required":0, | |
52 | # "data_digest_required":0 | |
53 | # } | |
54 | # ], | |
55 | # "hfi":[ | |
56 | # { | |
57 | # "index":1, | |
58 | # "transport":"tcp", | |
59 | # "pcidev":"0:0:2.0", | |
60 | # "mac_addr":"52:54:00:4f:97:e9", | |
61 | # "vlan":0, | |
62 | # "ip_origin":63, | |
63 | # "ipaddr":"192.168.100.217", | |
64 | # "subnet_mask_prefix":24, | |
65 | # "gateway_ipaddr":"0.0.0.0", | |
66 | # "route_metric":0, | |
67 | # "primary_dns_ipaddr":"0.0.0.0", | |
68 | # "secondary_dns_ipaddr":"0.0.0.0", | |
69 | # "dhcp_server_ipaddr":"", | |
70 | # "this_hfi_is_default_route":1 | |
71 | # } | |
72 | # ], | |
73 | # "discovery":[ | |
74 | # ] | |
75 | # } | |
76 | # ] | |
77 | # | |
78 | # If the IP address is derived from DHCP, it sets the field | |
79 | # "hfi.dhcp_server_ipaddr" to a non-emtpy value. | |
80 | # | |
81 | # | |
82 | ||
83 | nbft_run_jq() { | |
84 | local st | |
85 | local opts="-e" | |
86 | ||
87 | while [ $# -gt 0 ]; do | |
88 | case $1 in | |
89 | -*) | |
90 | opts="$opts $1" | |
91 | ;; | |
92 | *) | |
93 | break | |
94 | ;; | |
95 | esac | |
96 | shift | |
97 | done | |
98 | # Not quoting is intentional here. We won't get glob expressions passed. | |
99 | # shellcheck disable=SC2086 | |
100 | jq $opts "$1" << EOF | |
101 | $2 | |
102 | EOF | |
103 | st=$? | |
104 | if [ $st -ne 0 ]; then | |
105 | warn "NBFT: jq error while processing \"$1\"" | |
106 | return $st | |
107 | else | |
108 | return 0 | |
109 | fi | |
110 | } | |
111 | ||
112 | nbft_check_empty_address() { | |
113 | # suppress meaningless or empty IP addresses | |
114 | # "null" is returned by jq if no match found for expression | |
115 | case $1 in | |
116 | null | "::" | "0.0.0.0") ;; | |
117 | *) | |
118 | echo "$1" | |
119 | ;; | |
120 | esac | |
121 | } | |
122 | ||
123 | nbft_parse_hfi() { | |
124 | # false positive of shellcheck - no expansion in variable assignments | |
125 | # shellcheck disable=2086 | |
126 | local hfi_json=$1 | |
127 | local mac iface ipaddr prefix vlan gateway dns1 dns2 hostname adrfam dhcp | |
128 | ||
129 | mac=$(nbft_run_jq -r .mac_addr "$hfi_json") || return 1 | |
130 | iface=$(set_ifname nbft "$mac") | |
131 | ||
132 | vlan=$(nbft_run_jq .vlan "$hfi_json") || vlan=0 | |
133 | # treat VLAN zero as "no vlan" | |
134 | [ "$vlan" -ne 0 ] || vlan= | |
135 | ||
136 | [ ! -e /tmp/net."${iface}${vlan:+.$vlan}".has_ibft_config ] || return 0 | |
137 | ||
138 | dhcp=$(nbft_run_jq -r .dhcp_server_ipaddr "$hfi_json") | |
139 | # We need to check $? here as the above is an assignment | |
140 | # shellcheck disable=2181 | |
141 | if [ $? -eq 0 ] && [ "$dhcp" ] && [ "$dhcp" != null ]; then | |
142 | case $dhcp in | |
143 | *:*) | |
144 | echo ip="$iface${vlan:+.$vlan}:dhcp6" | |
145 | ;; | |
146 | *.*.*.*) | |
147 | echo ip="$iface${vlan:+.$vlan}:dhcp" | |
148 | ;; | |
149 | *) | |
150 | warn "Invalid value for dhcp_server_ipaddr: $dhcp" | |
151 | return 1 | |
152 | ;; | |
153 | esac | |
154 | else | |
155 | ipaddr=$(nbft_run_jq -r .ipaddr "$hfi_json") || return 1 | |
156 | ||
157 | case $ipaddr in | |
158 | *.*.*.*) | |
159 | adrfam=ipv4 | |
160 | ;; | |
161 | *:*) | |
162 | adrfam=ipv6 | |
163 | ;; | |
164 | *) | |
165 | warn "invalid address: $ipaddr" | |
166 | return 1 | |
167 | ;; | |
168 | esac | |
169 | prefix=$(nbft_run_jq -r .subnet_mask_prefix "$hfi_json") | |
170 | # Need to check $? here as he above is an assignment | |
171 | # shellcheck disable=2181 | |
172 | if [ $? -ne 0 ] && [ "$adrfam" = ipv6 ]; then | |
173 | prefix=128 | |
174 | fi | |
175 | # Use brackets for IPv6 | |
176 | if [ "$adrfam" = ipv6 ]; then | |
177 | ipaddr="[$ipaddr]" | |
178 | fi | |
179 | ||
180 | gateway=$(nbft_check_empty_address \ | |
181 | "$(nbft_run_jq -r .gateway_ipaddr "$hfi_json")") | |
182 | dns1=$(nbft_check_empty_address \ | |
183 | "$(nbft_run_jq -r .primary_dns_ipaddr "$hfi_json")") | |
184 | dns2=$(nbft_check_empty_address \ | |
185 | "$(nbft_run_jq -r .secondary_dns_ipaddr "$hfi_json")") | |
186 | hostname=$(nbft_run_jq -r .host_name "$hfi_json" 2> /dev/null) || hostname= | |
187 | ||
188 | echo "ip=$ipaddr::$gateway:$prefix:$hostname:$iface${vlan:+.$vlan}:none${dns1:+:$dns1}${dns2:+:$dns2}" | |
189 | fi | |
190 | ||
191 | if [ "$vlan" ]; then | |
192 | echo "vlan=$iface.$vlan:$iface" | |
193 | echo "$mac" > "/tmp/net.$iface.$vlan.has_ibft_config" | |
194 | else | |
195 | echo "$mac" > "/tmp/net.$iface.has_ibft_config" | |
196 | fi | |
197 | : > /tmp/valid_nbft_entry_found | |
198 | } | |
199 | ||
200 | nbft_parse() { | |
201 | local nbft_json n_nbft all_hfi_json n_hfi | |
202 | local j=0 i | |
203 | ||
204 | nbft_json=$(nvme nbft show -H -o json) || return 0 | |
205 | n_nbft=$(nbft_run_jq ". | length" "$nbft_json") || return 0 | |
206 | ||
207 | while [ "$j" -lt "$n_nbft" ]; do | |
208 | all_hfi_json=$(nbft_run_jq ".[$j].hfi" "$nbft_json") || continue | |
209 | n_hfi=$(nbft_run_jq ". | length" "$all_hfi_json") || continue | |
210 | i=0 | |
211 | ||
212 | while [ "$i" -lt "$n_hfi" ]; do | |
213 | nbft_parse_hfi "$(nbft_run_jq ".[$i]" "$all_hfi_json")" | |
214 | i=$((i + 1)) | |
215 | done | |
216 | j=$((j + 1)) | |
217 | done >> /etc/cmdline.d/40-nbft.conf | |
218 | } | |
019610af | 219 | |
9a52c3fd | 220 | if getargbool 0 rd.nonvmf; then |
019610af EM |
221 | warn "rd.nonvmf=0: skipping nvmf" |
222 | return 0 | |
223 | fi | |
224 | ||
b490f6f7 MW |
225 | if getargbool 0 rd.nvmf.nostatic; then |
226 | rm -f /etc/cmdline.d/95nvmf-args.conf | |
227 | rm -f /etc/nvme/discovery.conf /etc/nvme/config.json | |
228 | fi | |
229 | ||
230 | if ! getargbool 0 rd.nvmf.nonbft; then | |
231 | for _x in /sys/firmware/acpi/tables/NBFT*; do | |
232 | if [ -f "$_x" ]; then | |
233 | nbft_parse | |
234 | break | |
235 | fi | |
236 | done | |
237 | fi | |
238 | ||
a3cf4ec9 | 239 | initqueue --onetime modprobe --all -b -q nvme_tcp nvme_core nvme_fabrics |
019610af | 240 | |
2f03d69f | 241 | parse_nvmf_discover() { |
4087fd4d HR |
242 | traddr="none" |
243 | trtype="none" | |
244 | hosttraddr="none" | |
245 | trsvcid=4420 | |
2f03d69f | 246 | OLDIFS="$IFS" |
4087fd4d | 247 | IFS=, |
c305877c HH |
248 | # shellcheck disable=SC2086 |
249 | set -- $1 | |
2f03d69f HR |
250 | IFS="$OLDIFS" |
251 | ||
252 | case $# in | |
253 | 2) | |
019610af EM |
254 | [ -n "$1" ] && trtype=$1 |
255 | [ -n "$2" ] && traddr=$2 | |
2f03d69f HR |
256 | ;; |
257 | 3) | |
019610af EM |
258 | [ -n "$1" ] && trtype=$1 |
259 | [ -n "$2" ] && traddr=$2 | |
260 | [ -n "$3" ] && hosttraddr=$3 | |
2f03d69f HR |
261 | ;; |
262 | 4) | |
019610af EM |
263 | [ -n "$1" ] && trtype=$1 |
264 | [ -n "$2" ] && traddr=$2 | |
265 | [ -n "$3" ] && hosttraddr=$3 | |
266 | [ -n "$4" ] && trsvcid=$4 | |
2f03d69f HR |
267 | ;; |
268 | *) | |
e405501e | 269 | warn "Invalid arguments for rd.nvmf.discover=$1" |
251b4247 | 270 | return 0 |
2f03d69f HR |
271 | ;; |
272 | esac | |
9a52c3fd | 273 | if [ "$traddr" = "none" ]; then |
2f03d69f | 274 | warn "traddr is mandatory for $trtype" |
9a52c3fd | 275 | return 0 |
2f03d69f | 276 | fi |
cf8986af MW |
277 | if [ "$trtype" = "tcp" ]; then |
278 | : > /tmp/nvmf_needs_network | |
279 | elif [ "$trtype" = "fc" ]; then | |
9a52c3fd | 280 | if [ "$traddr" = "auto" ]; then |
f07117d6 | 281 | rm -f /etc/nvme/discovery.conf /etc/nvme/config.json |
251b4247 HR |
282 | return 1 |
283 | fi | |
9a52c3fd | 284 | if [ "$hosttraddr" = "none" ]; then |
2f03d69f | 285 | warn "host traddr is mandatory for fc" |
251b4247 | 286 | return 0 |
2f03d69f | 287 | fi |
cf8986af | 288 | elif [ "$trtype" != "rdma" ]; then |
2f03d69f | 289 | warn "unsupported transport $trtype" |
251b4247 | 290 | return 0 |
019610af | 291 | fi |
9a52c3fd | 292 | if [ "$trtype" = "fc" ]; then |
4087fd4d HR |
293 | echo "--transport=$trtype --traddr=$traddr --host-traddr=$hosttraddr" >> /etc/nvme/discovery.conf |
294 | else | |
295 | echo "--transport=$trtype --traddr=$traddr --host-traddr=$hosttraddr --trsvcid=$trsvcid" >> /etc/nvme/discovery.conf | |
296 | fi | |
251b4247 | 297 | return 0 |
2f03d69f HR |
298 | } |
299 | ||
e405501e | 300 | nvmf_hostnqn=$(getarg rd.nvmf.hostnqn -d nvmf.hostnqn=) |
9a52c3fd | 301 | if [ -n "$nvmf_hostnqn" ]; then |
2f03d69f HR |
302 | echo "$nvmf_hostnqn" > /etc/nvme/hostnqn |
303 | fi | |
e405501e | 304 | nvmf_hostid=$(getarg rd.nvmf.hostid -d nvmf.hostid=) |
9a52c3fd | 305 | if [ -n "$nvmf_hostid" ]; then |
2f03d69f HR |
306 | echo "$nvmf_hostid" > /etc/nvme/hostid |
307 | fi | |
308 | ||
b490f6f7 | 309 | rm -f /tmp/nvmf-fc-auto |
e405501e | 310 | for d in $(getargs rd.nvmf.discover -d nvmf.discover=); do |
556ef46a | 311 | parse_nvmf_discover "$d" || { |
b490f6f7 | 312 | : > /tmp/nvmf-fc-auto |
556ef46a MW |
313 | break |
314 | } | |
2f03d69f HR |
315 | done |
316 | ||
b490f6f7 | 317 | if [ -e /tmp/nvmf_needs_network ] || [ -e /tmp/valid_nbft_entry_found ]; then |
cf8986af | 318 | echo "rd.neednet=1" > /etc/cmdline.d/nvmf-neednet.conf |
b490f6f7 MW |
319 | # netroot is a global variable that is present in all "sourced" scripts |
320 | # shellcheck disable=SC2034 | |
321 | netroot=nbft | |
cf8986af MW |
322 | rm -f /tmp/nvmf_needs_network |
323 | fi | |
324 | ||
b490f6f7 MW |
325 | /sbin/initqueue --settled --onetime --name nvmf-connect-settled /sbin/nvmf-autoconnect.sh settled |
326 | /sbin/initqueue --timeout --onetime --name nvmf-connect-timeout /sbin/nvmf-autoconnect.sh timeout |