setup-interfaces.in 10.6 KB
Newer Older
Natanael Copa's avatar
Natanael Copa committed
1 2 3 4 5
#!/bin/sh

PROGRAM=setup-interfaces
PREFIX=

6 7
PKGS=

Natanael Copa's avatar
Natanael Copa committed
8 9 10
for i in ./libalpine.sh $PREFIX/lib/libalpine.sh; do
	[ -e $i ] && . $i && break
done
Natanael Copa's avatar
Natanael Copa committed
11

12 13 14 15
unconfigured_add() {
	touch $1.noconf
}

Natanael Copa's avatar
Natanael Copa committed
16 17 18 19
unconfigured_detect() {
	local i=
	for i in ${INTERFACES:-$(available_ifaces)}; do
		if [ "$i" != "lo" ]; then
20
			unconfigured_add $i
Natanael Copa's avatar
Natanael Copa committed
21 22
		fi
	done
Natanael Copa's avatar
Natanael Copa committed
23 24
}

Natanael Copa's avatar
Natanael Copa committed
25
unconfigured_get_first() {
Natanael Copa's avatar
Natanael Copa committed
26 27 28
	ls *.noconf 2>/dev/null | head -n 1 | sed 's/.noconf//'
}

Natanael Copa's avatar
Natanael Copa committed
29
unconfigured_del() {
30
	rm -f $1.noconf
Natanael Copa's avatar
Natanael Copa committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
}

unconfigured_all_done() {
	local i=
	for i in *.noconf; do
		[ -e $i ] && return 1
	done
	return 0
}

unconfigured_list() {
	local list= i=
	for i in *.noconf; do
		[ -e "$i" ] || continue
		list="${list} ${i%.noconf}"
	done
	echo $list
}

unconfigured_isin() {
	[ -f $1.noconf ]
}

54 55 56 57
iface_exists() {
	test -e /sys/class/net/$1
}

Natanael Copa's avatar
Natanael Copa committed
58 59 60 61
get_default_addr() {
	# check if dhcpcd is running
	if pidof dhcpcd > /dev/null && [ -f "$ROOT/var/lib/dhcpc/dhcpcd-$1.info" ]; then
		echo dhcp
62
	elif iface_exists $1; then
Natanael Copa's avatar
Natanael Copa committed
63
		ip addr show $1 | awk '/inet / {print $2}' | head -n 1 | sed 's:/.*::'
64
	fi
Natanael Copa's avatar
Natanael Copa committed
65 66 67 68 69 70 71 72 73 74 75
}

get_default_mask() {
	if [ "$1" ] ; then
		ipcalc -m $1 | sed 's/.*=//'
	else
		echo "255.255.255.0"
	fi
}

get_default_gateway() {
76 77 78
	if iface_exists $1; then
		ip route show dev $1 | awk '/^default/ {print $3}'
	fi
Natanael Copa's avatar
Natanael Copa committed
79 80
}

81 82 83
ipaddr_help() {
	cat <<__EOF__

84
Select the ip address for this interface.
85

86 87 88 89 90 91
dhcp				      Dynamic/automatic ip via DHCP
none				      Do not add any address
n.n.n.n		(ex: 192.168.0.1)     Static ip
n.n.n.n/m	(ex: 192.168.0.1/24)  Static ip with mask
br[0-9]+	(ex: br0)	      Add this interface to a bridge
bridge[0-9]	(ex: bridge0)	      Add this interface to a bridge
92

93
You will be prompted for netmask if not specified with the address.
94 95 96

__EOF__
}
Natanael Copa's avatar
Natanael Copa committed
97

98
bridge_add_port() {
99 100 101 102 103 104 105 106 107
	local bridge=$1 iface=
	shift
	for iface; do
		echo $iface >> $bridge.bridge_ports
		unconfigured_add $bridge
		unconfigured_del $iface
	done
}

108 109 110 111 112 113
bridge_list_ports() {
	if [ -r $1.bridge_ports ]; then
		echo $(cat $1.bridge_ports)
	fi
}

114 115 116 117
is_bridge() {
	test -r $1.bridge_ports
}

Natanael Copa's avatar
Natanael Copa committed
118 119
config_iface() {
	local iface=$1
120
	local prefix=$2
121
	local default_address=$3
122
	local address= netmask= gateway= bridge_ports=
123
	local bridge
124
	local conf=$prefix$iface.conf
125
	local answer=
126

127
	while [ -n "$ask_bridge" ] && ! is_bridge $iface; do
128
		ask "Do you want to bridge the interface $iface?" yes
129 130
		case "$resp" in
			yes|y) resp=yes; break;;
131 132 133
			no|n) break;;
		esac
	done
134

135
	if [ "$resp" = "yes" ]; then
136
		bridge="br"`echo $iface | sed 's/[^0-9]//g'`
137
		ask "Name of the bridge you want add $iface to:" $bridge
138
		bridge_add_port $resp $iface
139
		return
140
	fi
141

142
	if [ -r "$iface.bridge_ports" ]; then
143
		bridge_ports=$(echo $(cat $iface.bridge_ports))
144 145
		echo "bridge_ports=\"$bridge_ports\"" >> $conf
	fi
146 147 148 149
	if [ -r "$iface.bond_slaves" ]; then
		bond_slaves=$(echo $(cat $iface.bond_slaves))
		echo "bond_slaves=\"$bond_slaves\"" >> $conf
	fi
150 151 152 153
	if [ -r "$iface.raw_device" ]; then
		raw_device=$(cat $iface.raw_device)
		echo "raw_device=\"$raw_device\"" >> $conf
	fi
154 155 156 157
	# use ipcalc to validate the address. we do accept /mask
	# we are no interested in the result, only error code, so
	# we send result to /dev/null
	while ! ipcalc -s -m $address >/dev/null 2>&1; do
158
		address=${default_address:-$(get_default_addr $iface)}
159
		[ -z "$address" ] && address="dhcp"
160
		ask "Ip address for $iface? (or 'dhcp', 'none', '?')" $address
161
		address=$resp
162 163 164 165
		case "$resp" in
		'?')	ipaddr_help;;
		"abort") return;;
		"dhcp")
166
			echo "type=dhcp" >> $conf
Natanael Copa's avatar
Natanael Copa committed
167
			unconfigured_del $iface
168
			return ;;
169 170 171 172
		"none")
			echo "type=manual" >> $conf
			unconfigured_del $iface
			return;;
173 174 175 176 177
		br[0-9]*|bridge[0-9]*)
			case "$iface" in
				# we dont allow bridge bridges
				br[0-9]*|bridge[0-9]*) continue;;
			esac
178
			bridge_add_port $resp $iface
179 180
			return ;;
		esac
Natanael Copa's avatar
Natanael Copa committed
181 182
	done

183 184 185 186 187 188 189 190
	# extract netmask if entered together with address
	if [ "$address" != "${address%%/*}" ]; then
		netmask=$(ipcalc -s -m $address | cut -d= -f2)
	fi

	# use ipcalc -m to validate netmask. we dont accept <addr>/mask suffix
	# so we pass on a dummy mask to ipcalc.
	while ! ipcalc -s -m $netmask/0 >/dev/null 2>&1; do
Natanael Copa's avatar
Natanael Copa committed
191
		netmask=`get_default_mask $address`
192 193
		ask "Netmask?" $netmask
		netmask=$resp
Natanael Copa's avatar
Natanael Copa committed
194 195 196
		[ "$netmask" = "abort" ] && return
	done

197 198 199
	# use ipcalc -m to validate netmask. we dont accept <addr>/mask suffix
	# so we pass on a dummy mask to ipcalc.
	while ! ipcalc -s -m $gateway/0 >/dev/null 2>&1; do
Natanael Copa's avatar
Natanael Copa committed
200 201
		gateway=`get_default_gateway $iface`
		[ -z "$gateway" ] && gateway=none
202 203
		ask "Gateway? (or 'none')" $gateway
		gateway=$resp
Natanael Copa's avatar
Natanael Copa committed
204 205 206 207 208
		[ "$gateway" = "abort" ] && return
		[ "$gateway" = "none" ] && gateway=""
		[ -z "$gateway" ] && break
	done
	
209
	echo "type=static" >> $conf
210 211 212
	if [ -n "$bridge_ports" ]; then
		echo "bridge_ports=$bridge_ports" >> $conf
	fi
213 214 215
	echo "address=${address%%/*}" >> $conf  #strip off /mask if there
	echo "netmask=$netmask" >> $conf
	echo "gateway=$gateway" >> $conf
216

217

218 219
	# print summary
	echo "Configuration for $iface:"
220
	sed 's/^/  /' $conf
Natanael Copa's avatar
Natanael Copa committed
221
	
Natanael Copa's avatar
Natanael Copa committed
222
	unconfigured_del $iface
Natanael Copa's avatar
Natanael Copa committed
223 224
}

225
is_bridge() {
226 227 228 229 230
	[ -e /sys/class/net/$1/bridge ] || [ -e $1.bridge_ports ]
}

is_bond_master() {
	[ -e $1.bond_slaves ]
231 232
}

233
unconfigured_available() {
234 235
	local local i= iflist=
	for i in $(unconfigured_list); do
236
		if ! is_bridge $i && ! is_bond_master $i; then
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
			iflist="${iflist}${iflist:+ }$i"
		fi
	done
	echo $iflist
}

unconfigured_all_are() {
	local i=
	for i; do
		unconfigured_isin $i || return 1
	done
	return 0
}

config_bridge() {
252
	local bridge=$1 iflist= i= ports=
253
	while ! unconfigured_all_done; do
254
		set -- $(unconfigured_available)
255
		[ $# -eq 0 ] && return 0;
256 257 258 259
		ports=$(bridge_list_ports $bridge)
		if [ -n "$ports" ]; then
			echo "Bridge ports in $bridge are: $ports"
		fi
260 261
		echo "Available bridge ports are: $@"
		ask "Which port(s) do you want add to bridge $bridge? (or 'done')" $1
262 263 264 265
		case $resp in
			'abort') return 1;;
			'done') return 0;;
		esac
266 267 268 269 270 271 272
		for i in $resp; do
			if unconfigured_isin $i; then
				bridge_add_port $bridge $i
			else
				echo "$i is not valid"
			fi
		done
273 274 275
	done
}

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
bond_add_slave() {
	local master=$1 slave=
	shift
	for slave; do
		echo $slave >> $master.bond_slaves
		unconfigured_add $master
		unconfigured_del $slave
	done
}

bond_list_slaves() {
	if [ -r $1.bond_slaves ]; then
		echo $(cat $1.bond_slaves)
	fi
}

config_bond() {
	local master=$1 slaves=
	while ! unconfigured_all_done; do
		set -- $(unconfigured_available)
		[ $# -eq 0 ] && return 0;
		slaves=$(bond_list_slaves $master)
		if [ -n "$slaves" ]; then
			echo "Bond slaves in $master are: $slaves"
		fi
		echo "Available bond slaves are: $@"
		ask "Which slave(s) do you want add to $master? (or 'done')" $1
		case $resp in
			'abort') return 1;;
			'done') return 0;;
		esac
		for i in $resp; do
			if unconfigured_isin $i; then
				bond_add_slave $master $i
			else
				echo "$i is not valid"
			fi
		done
	done
}

317 318 319 320 321 322 323 324 325 326 327 328
config_vlan() {
	local iface=$1 vid= raw_device=
	case $iface in
	*.*)	raw_device=${iface%.*}
		vid=${iface#*.}
		;;
	vlan*)	vid=${iface#vlan}
		ask_which "raw device" "do you want use for $iface" "$(unconfigured_list)"
		echo "$resp" > $iface.raw_device
		return 0
		;;
	esac
329 330 331
	if unconfigured_isin $raw_device || is_bond_master $raw_device; then
		return 0
	fi
332 333 334 335
	echo "$raw_device is not a valid raw device for $iface"
	return 1
}

336 337
usage() {
        cat <<__EOF__
338
usage: setup-interfaces [-bhi] [-p ROOT]
Natanael Copa's avatar
Natanael Copa committed
339

340
Setup network interfaces
Natanael Copa's avatar
Natanael Copa committed
341

342
options:
343
 -b  Ask for bridging of interfaces
344 345
 -h  Show this help
 -i  Read new contents of /etc/network/interfaces from stdin
346
 -p  Use ROOT as system prefix
347 348 349
__EOF__
        exit 1
}
Natanael Copa's avatar
Natanael Copa committed
350

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
iface_help() {
	cat <<__EOF__

Select the interface you wish to configure.

For advanced configurations, you can also enter:
br[0-9]+	(ex: br0)	bridge interface
bridge[0-9]+	(ex: bridge0)	bridge interface
bond[0-9]+	(ex: bond32)	bonded interface
vlan[0-9]+	(ex: vlan371)	vlan interface
eth?.[0-9]+	(ex: eth0.371)	vlan interface
bond?.[0.9]+	(ex: bond0.371)	vlan interface

You will be asked which physical interface(s) to
be used for advanced configurations.

__EOF__
}
Natanael Copa's avatar
Natanael Copa committed
369
prompt_for_interfaces() {
370 371 372
	init_tmpdir TMP
	
	cd $TMP
Natanael Copa's avatar
Natanael Copa committed
373
	unconfigured_detect
374 375
	
	index=1
Natanael Copa's avatar
Natanael Copa committed
376 377
	while ! unconfigured_all_done; do
		echo "Available interfaces are: $(unconfigured_list)."
378 379
		echo "Enter '?' for help on bridges, bonding and vlans."
		ask "Which one do you want to initialize? (or '?' or 'done')" \
380 381
			$(unconfigured_get_first)
		iface=$resp
382
	
383 384
		case "$iface" in
			"done") break;;
385
			'?') iface_help; continue;;
386 387
			br[0-9]*|bridge[0-9]*|virbr[0-9]*)
				config_bridge $iface || continue;;
388 389 390 391 392 393
			bond[0-9]*.[0-9]*)
				config_bond ${iface%.*} || continue
				config_iface ${iface%.*} $(printf "%.3d~" $index) none
				index=$(( $index + 1 ))
				config_vlan $iface || continue
				;;
394 395
			bond[0-9]*)
				config_bond $iface || continue;;
396 397
			*.[0-9]*|vlan[0-9]*)
				config_vlan $iface || continue;;
398 399
			*) unconfigured_isin $iface || continue;;
		esac
400 401 402 403 404 405
		config_iface $iface $(printf "%.3d~" $index)
		index=$(( $index + 1 ))
	done
	
	echo "type=loopback" > 000~lo.conf
	echo "" > interface
Natanael Copa's avatar
Natanael Copa committed
406
	hostname=$(cat $ROOT/etc/hostname 2>/dev/null)
407 408 409 410
	
	for i in *.conf ; do
		iface=`basename $i .conf`
		iface=${iface#[0-9]*~}
411
		bridge_ports=
412
		bond_slaves=
413
		raw_device=
414 415 416
		address=
		type=
		gateway=
417
		. ./$i
418 419
		echo "auto $iface" >> interfaces
		echo "iface $iface inet $type" >> interfaces
420
		if [ -n "$bridge_ports" ]; then
421
			PKGS="$PKGS bridge"
422 423
			echo -e "\tbridge-ports $bridge_ports" >> interfaces
		fi
424
		if [ -n "$bond_slaves" ]; then
425
			PKGS="$PKGS bonding"
426 427
			echo -e "\tbond-slaves $bond_slaves" >> interfaces
		fi
428
		if [ -n "$raw_device" ]; then
429
			echo -e "\tvlan-raw-device $raw_device" >> interfaces
430 431 432 433
		fi
		case "$iface" in
			*.[0-9]*|vlan[0-9]*) PKGS="$PKGS vlan";;
		esac
434
		case $type in
435 436 437 438
		manual)
			echo -e "\tup ip link set \$IFACE up" >> interfaces
			echo -e "\tdown ip link set \$IFACE down" >> interfaces
			;;
439 440 441 442 443 444 445 446 447 448 449
		dhcp)
			[ -n "$hostname" ] \
				&& echo -e "\thostname $hostname" >> interfaces
			;;
		static)
			echo -e "\taddress $address" >> interfaces
			echo -e "\tnetmask $netmask" >> interfaces
			[ "$gateway" ] \
				&& echo -e "\tgateway $gateway" >> interfaces
			;;
		esac
450
		echo "" >> interfaces
451 452 453
	done
	
	while [ "$answer" != "yes" ] && [ "$answer" != "no" ] ; do
454
		ask "Do you want to do any manual network configuration?" no
455 456 457 458 459
		case $resp in
			y) answer=yes;;
			n) answer=no;;
			*) answer=$resp;;
		esac
460
	done
Natanael Copa's avatar
Natanael Copa committed
461

462
	if yesno "$answer"; then
463
		case "$EDITOR" in
464 465
			nano)	apk add nano;;
			vim)	apk add vim;;
466 467 468
		esac
		${EDITOR:-vi} interfaces
	fi
469 470 471 472 473

	if [ -n "$PKGS" ]; then
		apk add -q $PKGS
	fi

474 475
	mkdir -p $ROOT/etc/network
	cp interfaces $ROOT/etc/network/
Natanael Copa's avatar
Natanael Copa committed
476 477
}

478 479 480
ask_bridge=
is_xen_dom0 && ask_bridge=1

Natanael Copa's avatar
Natanael Copa committed
481
while getopts "bhip:" opt; do
Natanael Copa's avatar
Natanael Copa committed
482
        case $opt in
483
		b) ask_bridge=1;;
Natanael Copa's avatar
Natanael Copa committed
484 485
                h) usage;;
		i) STDINPUT=1;;
Natanael Copa's avatar
Natanael Copa committed
486
		p) ROOT=$OPTARG;;
Natanael Copa's avatar
Natanael Copa committed
487 488 489
        esac
done

Natanael Copa's avatar
Natanael Copa committed
490
mkdir -p $ROOT/etc/network
Natanael Copa's avatar
Natanael Copa committed
491 492 493 494
if [ "$STDINPUT" = "1" ]; then
	cat > $ROOT/etc/network/interfaces
else
	prompt_for_interfaces
Natanael Copa's avatar
Natanael Copa committed
495
fi