f8288bbfe960dacd0e6ed3095376003e86565406
[platform/upstream/dracut.git] / modules.d / 40network / net-lib.sh
1 #!/bin/sh
2 # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3 # ex: ts=8 sw=4 sts=4 et filetype=sh
4
5 get_ip() {
6     local iface="$1" ip=""
7     ip=$(ip -o -f inet addr show $iface)
8     ip=${ip%%/*}
9     ip=${ip##* }
10 }
11
12 iface_for_remote_addr() {
13     set -- $(ip -o route get to $1)
14     echo $5
15 }
16
17 iface_for_mac() {
18     local interface="" mac="$(echo $1 | sed 'y/ABCDEF/abcdef/')"
19     for interface in /sys/class/net/*; do
20         if [ $(cat $interface/address) = "$mac" ]; then
21             echo ${interface##*/}
22         fi
23     done
24 }
25
26 iface_has_link() {
27     local interface="$1" flags=""
28     [ -n "$interface" ] || return 2
29     interface="/sys/class/net/$interface"
30     [ -d "$interface" ] || return 2
31     flags=$(cat $interface/flags)
32     echo $(($flags|0x41)) > $interface/flags # 0x41: IFF_UP|IFF_RUNNING
33     [ "$(cat $interface/carrier)" = 1 ] || return 1
34     # XXX Do we need to reset the flags here? anaconda never bothered..
35 }
36
37 all_ifaces_up() {
38     local iface="" IFACES=""
39     [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
40     for iface in $IFACES; do
41         [ -e /tmp/net.$iface.up ] || return 1
42     done
43 }
44
45 get_netroot_ip() {
46     local prefix="" server="" rest=""
47     splitsep "$1" ":" prefix server rest
48     case $server in
49         [0-9]*\.[0-9]*\.[0-9]*\.[0-9]*) echo "$server"; return 0 ;;
50     esac
51     return 1
52 }
53
54 ip_is_local() {
55     strstr "$(ip route get $1 2>/dev/null)" " via "
56 }
57
58 ifdown() {
59     local netif="$1"
60     # ip down/flush ensures that routing info goes away as well
61     ip link set $netif down
62     ip addr flush dev $netif
63     echo "#empty" > /etc/resolv.conf
64     rm -f /tmp/net.$netif.did-setup
65     # TODO: send "offline" uevent?
66 }
67
68 setup_net() {
69     local netif="$1" f="" gw_ip="" netroot_ip="" iface="" IFACES=""
70     [ -e /tmp/net.$netif.did-setup ] && return
71     [ -e "/tmp/net.ifaces" ] && read IFACES < /tmp/net.ifaces
72     [ -z "$IFACES" ] && IFACES="$netif"
73     # run the scripts written by ifup
74     [ -e /tmp/net.$netif.gw ]            && . /tmp/net.$netif.gw
75     [ -e /tmp/net.$netif.hostname ]      && . /tmp/net.$netif.hostname
76     [ -e /tmp/net.$netif.override ]      && . /tmp/net.$netif.override
77     [ -e /tmp/dhclient.$netif.dhcpopts ] && . /tmp/dhclient.$netif.dhcpopts
78     # set up resolv.conf
79     [ -e /tmp/net.$netif.resolv.conf ] && \
80         cp -f /tmp/net.$netif.resolv.conf /etc/resolv.conf
81
82     # Handle STP Timeout: arping the default gateway.
83     # (or the root server, if a) it's local or b) there's no gateway.)
84     # Note: This assumes that if no router is present the
85     # root server is on the same subnet.
86
87     # Get DHCP-provided router IP, or the cmdline-provided "gw=" argument
88     [ -n "$new_routers" ] && gw_ip=${new_routers%%,*}
89     [ -n "$gw" ] && gw_ip=$gw
90
91     # Get the "netroot" IP (if there's an IP address in there)
92     netroot_ip=$(get_netroot_ip $netroot)
93
94     # try netroot if it's local (or there's no gateway)
95     if ip_is_local $netroot_ip || [ -z "$gw_ip" ]; then
96         dest="$netroot_ip"
97     else
98         dest="$gw_ip"
99     fi
100
101     unset layer2
102     if [ -f /sys/class/net/$netif/device/layer2 ]; then
103         read layer2 < /sys/class/net/$netif/device/layer2
104     fi
105
106     if [ "$layer2" != "0" ] && [ -n "$dest" ] && ! arping -q -f -w 60 -I $netif $dest ; then
107         info "Resolving $dest via ARP on $netif failed"
108     fi
109     unset layer2
110
111     > /tmp/net.$netif.did-setup
112 }
113
114 save_netinfo() {
115     local netif="$1" IFACES="" f="" i=""
116     [ -e /tmp/net.ifaces ] && read IFACES < /tmp/net.ifaces
117     # Add $netif to the front of IFACES (if it's not there already).
118     set -- "$netif"
119     for i in $IFACES; do [ "$i" != "$netif" ] && set -- "$@" "$i"; done
120     IFACES="$*"
121     for i in $IFACES; do
122         for f in /tmp/dhclient.$i.*; do
123             [ -f $f ] && cp -f $f /tmp/net.${f#/tmp/dhclient.}
124         done
125     done
126     echo $IFACES > /tmp/.net.ifaces.new
127     mv /tmp/.net.ifaces.new /tmp/net.ifaces
128 }
129
130 set_ifname() {
131     local name="$1" mac="$2" num=0 n=""
132     # if it's already set, return the existing name
133     for n in $(getargs ifname=); do
134         strstr "$n" "$mac" && echo ${n%%:*} && return
135     done
136     # otherwise, pick a new name and use that
137     while [ -e /sys/class/$name$num ]; do num=$(($num+1)); done
138     echo "ifname=$name$num:$mac" >> /etc/cmdline.d/45-ifname.conf
139     echo "$name$num"
140 }
141
142 ibft_to_cmdline() {
143     local iface="" mac="" dev=""
144     local dhcp="" ip="" gw="" mask="" hostname=""
145     modprobe -q iscsi_ibft
146     (
147         for iface in /sys/firmware/ibft/ethernet*; do
148             [ -e ${iface}/mac ] || continue
149             mac=$(read a < ${iface}/mac; echo $a)
150             [ -z "$mac" ] && continue
151             dev=$(set_ifname ibft $mac)
152             dhcp=$(read a < ${iface}/dhcp; echo $a)
153             if [ -n "$dhcp" ]; then
154                 echo "ip=$dev:dhcp"
155             else
156                 ip=$(read a < ${iface}/ip-addr; echo $a)
157                 gw=$(read a < ${iface}/gateway; echo $a)
158                 mask=$(read a < ${iface}/subnet-mask; echo $a)
159                 hostname=$(read a < ${iface}/hostname; echo $a)
160                 echo "ip=$ip::$gw:$mask:$hostname:$dev:none"
161             fi
162             echo $mac > /tmp/net.${dev}.has_ibft_config
163         done
164     ) >> /etc/cmdline.d/40-ibft.conf
165     # reread cmdline
166     unset CMDLINE
167 }
168
169 parse_iscsi_root()
170 {
171     local v
172     v=${1#iscsi:}
173
174 # extract authentication info
175     case "$v" in
176         *@*:*:*:*:*)
177             authinfo=${v%%@*}
178             v=${v#*@}
179     # allow empty authinfo to allow having an @ in iscsi_target_name like this:
180     # netroot=iscsi:@192.168.1.100::3260::iqn.2009-01.com.example:testdi@sk
181             if [ -n "$authinfo" ]; then
182                 OLDIFS="$IFS"
183                 IFS=:
184                 set $authinfo
185                 IFS="$OLDIFS"
186                 if [ $# -gt 4 ]; then
187                     warn "Wrong authentication info in iscsi: parameter!"
188                     return 1
189                 fi
190                 iscsi_username=$1
191                 iscsi_password=$2
192                 if [ $# -gt 2 ]; then
193                     iscsi_in_username=$3
194                     iscsi_in_password=$4
195                 fi
196             fi
197             ;;
198     esac
199
200 # extract target ip
201     case "$v" in
202         [[]*[]]:*)
203             iscsi_target_ip=${v#[[]}
204                 iscsi_target_ip=${iscsi_target_ip%%[]]*}
205             v=${v#[[]$iscsi_target_ip[]]:}
206             ;;
207         *)
208             iscsi_target_ip=${v%%[:]*}
209             v=${v#$iscsi_target_ip:}
210             ;;
211     esac
212
213 # extract target name
214     case "$v" in
215         *:iqn.*)
216             iscsi_target_name=iqn.${v##*:iqn.}
217             v=${v%:iqn.*}:
218             ;;
219         *:eui.*)
220             iscsi_target_name=iqn.${v##*:eui.}
221             v=${v%:iqn.*}:
222             ;;
223         *:naa.*)
224             iscsi_target_name=iqn.${v##*:naa.}
225             v=${v%:iqn.*}:
226             ;;
227         *)
228             warn "Invalid iscii target name, should begin with 'iqn.' or 'eui.' or 'naa.'"
229             return 1
230             ;;
231     esac
232
233 # parse the rest
234     OLDIFS="$IFS"
235     IFS=:
236     set $v
237     IFS="$OLDIFS"
238
239     iscsi_protocol=$1; shift # ignored
240     iscsi_target_port=$1; shift
241     if [ $# -eq 3 ]; then
242         iscsi_iface_name=$1; shift
243     fi
244     if [ $# -eq 2 ]; then
245         iscsi_netdev_name=$1; shift
246     fi
247     iscsi_lun=$1; shift
248     if [ $# -ne 0 ]; then
249         warn "Invalid parameter in iscsi: parameter!"
250         return 1
251     fi
252 }
253
254 ip_to_var() {
255     local v=${1}:
256     local i
257     set --
258     while [ -n "$v" ]; do
259         if [ "${v#\[*:*:*\]:}" != "$v" ]; then
260             # handle IPv6 address
261             i="${v%%\]:*}"
262             i="${i##\[}"
263             set -- "$@" "$i"
264             v=${v#\[$i\]:}
265         else
266             set -- "$@" "${v%%:*}"
267             v=${v#*:}
268         fi
269     done
270
271     unset ip srv gw mask hostname dev autoconf macaddr mtu
272     case $# in
273         0)  autoconf="error" ;;
274         1)  autoconf=$1 ;;
275         2)  [ -n "$1" ] && dev=$1; [ -n "$2" ] && autoconf=$2 ;;
276         3)  [ -n "$1" ] && dev=$1; [ -n "$2" ] && autoconf=$2; [ -n "$3" ] && mtu=$3 ;;
277         4)  [ -n "$1" ] && dev=$1; [ -n "$2" ] && autoconf=$2; [ -n "$3" ] && mtu=$3; [ -n "$4" ] && macaddr=$4 ;;
278         *)  [ -n "$1" ] && ip=$1; [ -n "$2" ] && srv=$2; [ -n "$3" ] && gw=$3; [ -n "$4" ] && mask=$4;
279             [ -n "$5" ] && hostname=$5; [ -n "$6" ] && dev=$6; [ -n "$7" ] && autoconf=$7; [ -n "$8" ] && mtu=$8;
280             if [ -n "${9}" -a -n "${10}" -a -n "${11}" -a -n "${12}" -a -n "${13}" -a -n "${14}" ]; then
281                 macaddr="${9}:${10}:${11}:${12}:${13}:${14}"
282             fi
283             ;;
284     esac
285     # anaconda-style argument cluster
286     if strstr "$autoconf" "*.*.*.*"; then
287         ip="$autoconf"
288         gw=$(getarg gateway=)
289         mask=$(getarg netmask=)
290         hostname=$(getarg hostname=)
291         dev=$(getarg ksdevice=)
292         autoconf="none"
293         mtu=$(getarg mtu=)
294         case "$dev" in
295             # ignore fancy values for ksdevice=XXX
296             link|bootif|BOOTIF|ibft|*:*:*:*:*:*) dev="" ;;
297         esac
298     fi
299 }
300
301 parse_ifname_opts() {
302     local IFS=:
303     set $1
304
305     case $# in
306         7)
307             ifname_if=$1
308             # udev requires MAC addresses to be lower case
309             ifname_mac=$(echo $2:$3:$4:$5:$6:$7 | sed 'y/ABCDEF/abcdef/')
310             ;;
311         *)
312             die "Invalid arguments for ifname="
313             ;;
314     esac
315
316     case $ifname_if in
317         eth[0-9]|eth[0-9][0-9]|eth[0-9][0-9][0-9]|eth[0-9][0-9][0-9][0-9])
318             warn "ifname=$ifname_if uses the kernel name space for interfaces"
319             warn "This can fail for multiple network interfaces and is discouraged!"
320             warn "Please use a custom name like \"netboot\" or \"bluesocket\""
321             warn "or use biosdevname and no ifname= at all."
322             ;;
323     esac
324
325 }
326
327 # some network driver need long time to initialize, wait before it's ready.
328 wait_for_if_link() {
329     local cnt=0
330     local li
331     while [ $cnt -lt 600 ]; do
332         li=$(ip -o link show dev $1 2>/dev/null)
333         [ -n "$li" ] && return 0
334         sleep 0.1
335         cnt=$(($cnt+1))
336     done
337     return 1
338 }
339
340 wait_for_if_up() {
341     local cnt=0
342     local li
343     while [ $cnt -lt 200 ]; do
344         li=$(ip -o link show up dev $1)
345         [ -n "$li" ] && return 0
346         sleep 0.1
347         cnt=$(($cnt+1))
348     done
349     return 1
350 }
351
352 wait_for_route_ok() {
353     local cnt=0
354     while [ $cnt -lt 200 ]; do
355         li=$(ip route show)
356         [ -n "$li" ] && [ -z "${li##*$1*}" ] && return 0
357         sleep 0.1
358         cnt=$(($cnt+1))
359     done
360     return 1
361 }
362
363 wait_for_ipv6_auto() {
364     local cnt=0
365     local li
366     while [ $cnt -lt 400 ]; do
367         li=$(ip -6 addr show dev $1)
368         strstr "$li" "dynamic" && return 0
369         sleep 0.1
370         cnt=$(($cnt+1))
371     done
372     return 1
373 }
374
375 linkup() {
376     wait_for_if_link $1 2>/dev/null\
377      && ip link set $1 up 2>/dev/null\
378      && wait_for_if_up $1 2>/dev/null
379 }
380
381 type hostname >/dev/null 2>&1 || \
382 hostname() {
383         cat /proc/sys/kernel/hostname
384 }