summaryrefslogtreecommitdiff
blob: f734e776c1db43c135de27b02688a33db7682aa3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#!/bin/bash
# Copyright (c) 2004-2005 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# Contributed by Roy Marples (uberlord@gentoo.org)

# Fix any potential localisation problems
# Note that LC_ALL trumps LC_anything_else according to locale(7)
ip() {
	LC_ALL=C /sbin/ip "$@"
}

iproute2_tunnel() {
	LC_ALL=C /sbin/ip tunnel "$@"
}

# void iproute2_depend(void)
#
# Sets up the dependancies for the module
iproute2_depend() {
	provide interface
	functions interface_device
	variables config routes fallback metric ipaddr ipaddr_fallback iproute inet6
}

# bool iproute2_check_installed(void)
#
# Returns 1 if iproute2 is installed, otherwise 0
iproute2_check_installed() {
	local report="${1:-false}" installed="0"
	if [[ ! -x /sbin/ip ]]; then
		installed="1"
		${report} && eerror "For iproute2 support, emerge sys-apps/iproute2"
	fi
	if [[ ! -e /proc/net/netlink ]]; then
		installed="1"
		${report} && eerror "iproute2 requires NetLink enabled in the kernel"
	fi
	return "${installed}"
}

# bool iproute2_exists(char *interface, bool report)
#
# Returns 1 if the interface exists, otherwise 0
iproute2_exists() {
	local e=$( ip addr show label "$1" ) report="${2:-false}"
	[[ -n ${e} ]] && return 0

	${report} && eerror "$1 does not exist"
	return 1
}

# void iproute2_up(char *interface)
#
# provides a generic interface for bringing interfaces up
iproute2_up() {
	ip link set up dev "$1"
}

# void iproute2_down(char *interface)
#
# provides a generic interface for bringing interfaces up
iproute2_down() {
	ip link set down dev "$1"
}

# bool ifproute2_is_up(char *iface, bool withaddress)
#
# Returns 0 if the interface is up, otherwise 1
# If withaddress is true then the interface has to have an IPv4 address
# assigned as well
iproute2_is_up() {
	local check="\<UP\>" addr="${2:-false}"
	${addr} && check="${check}.*inet "
	ip addr show "$1" | xargs | grep -Eq "${check}" && return 0
	return 1
}

# void iproute2_set_flag(char *iface, char *flag, bool enabled)
#
# Sets or disables the interface flag 
iproute2_set_flag() {
	local enable="$3" opt="on"
	${enable} || opt="off"
	ip link set "$1" "$2" "${opt}"
}

# void iproute2_get_address(char *interface)
#
# Fetch the address retrieved by DHCP.  If successful, echoes the
# address on stdout, otherwise echoes nothing.
iproute2_get_address() {
	ip -family inet addr show "$1" \
	| sed -n -e 's/.*inet \([^ ]*\).*/\1/p'
}

# void iproute2_get_mac_address(char *interface)
#
# Fetch the mac address assingned to the network card
iproute2_get_mac_address() {
	local mac=$( ip link show "$1" | sed -n -e \
		's/^.*\<\(..:..:..:..:..:..\)\>.*/\U\1/p' )
	[[ ${mac} != '00:00:00:00:00:00' \
	&& ${mac} != '44:44:44:44:44:44' \
	&& ${mac} != 'FF:FF:FF:FF:FF:FF' ]] \
		&& echo "${mac}"
}

# void iproute2_set_mac_address(char *interface, char *mac)
#
# Assigned the mac address to the network card
iproute2_set_mac_address() {
	ip link set address "$2" dev "$1"
}

# int iproute2_set_name(char *interface, char *new_name)
#
# Renames the interface
# This will not work if the interface is setup!
iproute2_set_name() {
	ip link set name "$2" dev "$1"
}

# void iproute2_get_aliases_rev(char *interface)
#
# Fetch the list of aliases for an interface.  
# Outputs a space-separated list on stdout, in reverse order, for
# example "eth0:2 eth0:1"
iproute2_get_aliases_rev() {
	local iface=$( interface_device "$1" )
	ip addr show dev "${iface}" | grep -o "${iface}:[0-9].*" | tac
}

# bool iproute2_del_addresses(char *interface, bool onlyinet)
#
# Remove addresses from interface.
# If onlyinet is true, then we only remove IPv4 / inet addresses.
iproute2_del_addresses() {
	local pre=""
	${2:-false} && pre="-f inet"
	ip ${pre} addr flush label "$1" scope global &>/dev/null
	ip ${pre} addr flush label "$1" scope host &>/dev/null
	return 0
}

# bool iproute2_get_old_config(char *iface)
#
# Returns config and config_fallback for the given interface
iproute2_get_old_config() {
	local ifvar=$( bash_variable "$1" ) inet6 t

	# iproute2-style config vars
	t="ipaddr_${ifvar}[@]"
	config=( "${!t}" )
	t="config_fallback_${ifvar}[@]"
	config_fallback=( "${!t}" )
	t="inet6_${ifvar}[@]"
	inet6=( "${!t}" )

	# BACKWARD COMPATIBILITY: check for space-separated inet6 addresses
	[[ ${#inet6[@]} == "1" && ${inet6} == *" "* ]] && inet6=( ${inet6} )

	# Add inet6 addresses to our config if required
	[[ -n ${inet6} ]] && config=( "${config[@]}" "${inet6[@]}" )

	# Support old style iface_xxx syntax
	if [[ -z ${config} ]] ; then
		if is_function ifconfig_get_old_config ; then
			ifconfig_get_old_config "${iface}"
		fi
	fi

	return 0
}

# bool iproute2_iface_stop(char *interface)
#
# Do final shutdown for an interface or alias.
#
# Returns 0 (true) when successful, non-zero (false) on failure
iproute2_iface_stop() {
	local label="$1" iface=$( interface_device "$1" )

	# Shut down the link if this isn't an alias or vlan
	if [[ ${label} == "${iface}" ]]; then
		iproute2_down "${iface}"
		return $?
	fi
	return 0
}

# bool iproute2_add_address(char *interface, char *options ...)
#
# Adds an the specified address to the interface
# returns 0 on success and non-zero on failure
iproute2_add_address() {
	local iface="$1" x

	iproute2_exists "${iface}" true || return 1

	# Extract the config
	local -a config=( "$@" )
	config=( ${config[@]:1} )

	# Convert an ifconfig line to iproute2
	local n="${#config[@]}"
	for (( x=0; x<n; x++ )); do
		case "${config[x]}" in
			netmask)
				config[0]="${config[0]}/$( netmask2cidr ${config[x+1]} )"
				unset config[x] config[x+1]
				;;
			mtu)
				ip link set mtu "${config[x+1]}" dev "${iface}"
				unset config[x] config[x+1]
				;;
		esac
	done
	config=( "${config[@]//pointopoint/peer}" )

	# Always scope lo addresses as host unless specified otherwise
	[[ ${iface} == "lo" && " ${config[@]} " != *" scope "* ]] \
	&& config=( "${config[@]}" "scope host" )

	# IPv4 specifics
	if [[ ${config[@]} == *.*.*.* ]]; then
		# Work out a broadcast if none supplied
		[[ ${config[@]} != *" brd "* && ${config[@]} != *" broadcast "* ]] \
			&& config=( "${config[@]}" "brd +" )
	fi

	# Ensure that the interface is up so we can add IPv6 addresses
	interface_up "${iface}"

	# Some kernels like to apply lo with an address when they are brought up
	if [[ ${iface} == "lo" \
		&& ${config[@]} == "127.0.0.1/8 brd 127.255.255.255 scope host" ]]; then
		ip addr del dev "${iface}" 127.0.0.1/8 2>/dev/null
	fi

	ip addr add dev "${iface}" ${config[@]}
	local r="$?"
	[[ ${r} != "0" ]] && return "${r}"

	local metric ifvar=$( bash_variable "${iface}" )
	# Remove the newly added route and replace with our metric
	metric="metric_${ifvar}"
	[[ ${!metric} == "0" || ${RC_AUTO_INTERFACE} != "yes" ]] && return "${r}"

	local network=$( ip_network "${config[0]}" )
	[[ -z ${network} ]] && return "${r}"

	local cidr="${config[0]##*/}"
	if ip route del "${network}/${cidr}" metric 0 dev "${iface}" \
		2>/dev/null ; then
		ip route add "${network}/${cidr}" metric "${!metric}" dev "${iface}"
	fi

	return "${r}"
}

# bool iproute2_pre_start(char *interface)
#
# Runs any pre_start stuff on our interface - just the MTU atm
# We set MTU twice as it may be needed for DHCP - a dhcp client could
# change it in error, so we set MTU in post start too
iproute2_pre_start() {
	local iface="$1"

	interface_exists "${iface}" || return 0

	local ifvar=$( bash_variable "$1" ) mtu

	# MTU support
	mtu="mtu_${ifvar}"
	[[ -n ${!mtu} ]] && ip link set mtu "${!mtu}" dev "${iface}"

	return 0
}

# bool iproute2_post_start(char *interface)
#
# Runs any post_start stuff on our interface and adds routes
# Always returns 0
iproute2_post_start() {
	local iface="$1" ifvar=$( bash_variable "$1" ) routes metric mtu x netmask

	iproute2_exists "${iface}" || return 0
	
	# Make sure interface is marked UP
	iproute2_up "${iface}"

	# MTU support
	mtu="mtu_${ifvar}"
	[[ -n ${!mtu} ]] && ip link set mtu "${!mtu}" dev "${iface}"

	x="routes_${ifvar}[@]"
	routes=( "${!x}" )
	metric="metric_${ifvar}"

	# Test for old style ipaddr variable
	if [[ -z ${routes} ]]; then
		t="iproute_${ifvar}[@]"
		routes=( "${!t}" )
	fi

	[[ -z ${routes} ]] && return 0

	# Set routes with ip route -- this might also include default route
	einfo "Adding routes"
	eindent
	for x in "${routes[@]}"; do
		ebegin "${x}"

		# Support net-tools routing too
		x="${x//gw/via}"
		x="${x//-A inet6/}"
		x="${x//-net/}"
		[[ " ${x} " == *" -host "* ]] && x="${x//-host/} scope host"

		# Attempt to support net-tools route netmask option
		netmask="${x##* netmask }"
		if [[ -n ${netmask} && ${x} != "${netmask}" ]]; then
			netmask="${netmask%% *}"
			x="${x// netmask ${netmask} / }"
			local -a a=( ${x} )
			a[0]="${a[0]}/$( netmask2cidr ${netmask} )"
			x="${a[@]}"
		fi

		# Add a metric if we don't have one
		[[ " ${x} " != *" metric "* ]] && x="${x} metric ${!metric}"

		ip route append ${x} dev "${iface}"
		eend $?
	done
	eoutdent

	return 0
}

# void iproute2_route_metric(char* interface, int metric)
#
# Change all routes for an interface to a given metric
iproute2_route_metric() {
	local route
	ip route | grep " dev $1" | {
		while read route ; do
			ip route del ${route}
			ip route add ${route} metric "$2"
		done
	}
}

# void iproute2_default_route(char* interface, char* gateway_ip, int metric)
#
# Force default route to the specified gateway, optionally on
# the given interface
iproute2_default_route() {
	local metric="${3:-0}"

	ip route change default via "$2" metric "${metric}" dev "$1" 2>/dev/null \
	|| ip route append default via "$2" metric "${metric}" dev "$1" 2>/dev/null
}

# vim:ts=4