summaryrefslogtreecommitdiff
path: root/net/vlan.sh
blob: 10040afa04d36ffcaf401dd9a87196b5f5f91032 (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
# Copyright (c) 2007-2008 Roy Marples <roy@marples.name>
# Released under the 2-clause BSD license.

vlan_depend()
{
	program ip
	after interface
	before dhcp
}

_config_vars="$_config_vars vlans"

_is_vlan()
{
	[ ! -d /proc/net/vlan ] && return 1
	[ -e /proc/net/vlan/"${IFACE}" ] && return 0
	grep -Eq "^${IFACE}[[:space:]]+" /proc/net/vlan/config
}

_get_vlans()
{
	[ -e /proc/net/vlan/config ] || return 1
	sed -n -e 's/^\W*\([^ ]*\) \(.* \) .*'"${IFACE}"'$/\1/p' /proc/net/vlan/config
}

_check_vlan()
{
	if [ ! -d /proc/net/vlan ]; then
		modprobe 8021q
		if [ ! -d /proc/net/vlan ]; then
			eerror "VLAN (802.1q) support is not present in this kernel"
			return 1
		fi
	fi
}

vlan_pre_start()
{
	local vconfig
	eval vconfig=\$vconfig_${IFVAR}
	if [ -n "${vconfig}" ]; then
		eerror "You must convert your vconfig_ VLAN entries to vlan${N} entries."
		return 1
	fi
	local vlans=
	eval vlans=\$vlans_${IFVAR}
	[ -z "$vlans" ] && return 0
	case " ${MODULES} " in
		*" ifconfig "*)
				eerror "sys-apps/iproute2 is required to configure VLANs"
				return 1 ;;
	esac
}

vlan_post_start()
{
	local vlans=
	eval vlans=\$vlans_${IFVAR}
	[ -z "${vlans}" ] && return 0

	_check_vlan || return 1
	_exists || return 1

	local vlan= e= s= vname= vflags= vingress= vegress=
	for vlan in ${vlans}; do
		einfo "Adding VLAN ${vlan} to ${IFACE}"
		# We need to gather all interface configuration options
		# 1) naming. Default to the standard "${IFACE}.${vlan}" but it can be anything
		eval vname=\$${IFACE}_vlan${vlan}_name
		[ -z "${vname}" ] && eval vname=\$vlan${vlan}_name
		[ -z "${vname}" ] && vname="${IFACE}.${vlan}"
		# 2) flags
		eval vflags=\$${IFACE}_vlan${vlan}_flags
		[ -z "${vflags}" ] && eval vflags=\$vlan${vlan}_flags
		# 3) ingress/egress map
		eval vingress=\$${IFACE}_vlan${vlan}_ingress
		[ -z "${vingress}" ] && eval vingress=\$vlan${vlan}_ingress
		[ -z "${vingress}" ] || vingress="ingress-qos-map ${vingress}"
		eval vegress=\$${IFACE}_vlan${vlan}_egress
		[ -z "${vegress}" ] && eval vegress=\$vlan${vlan}_egress
		[ -z "${vegress}" ] || vegress="egress-qos-map ${vegress}"

		# txqueue
		local txqueuelen=
		eval txqueuelen=\$txqueuelen_${IFACE}_vlan${vlan}
		[ -z "${txqueuelen}" ] && eval txqueuelen=\$txqueuelen_vlan${vlan}
		# mac
		local mac=
		eval mac=\$mac_${IFACE}_vlan${vlan}
		[ -z "${mac}" ] && eval mac=\$mac_vlan${vlan}
		# broadcast
		local broadcast=
		eval broadcast=\$broadcast_${IFACE}_vlan${vlan}
		[ -z "${broadcast}" ] && eval broadcast=\$broadcast_vlan${vlan}
		# mtu
		local mtu=
		eval mtu=\$mtu_${IFACE}_vlan${vlan}
		[ -z "${mtu}" ] && eval mtu=\$mtu_vlan${vlan}

		# combine it all
		local opts="${txqueuelen:+txqueuelen} ${txqueuelen} ${mac:+address} ${mac} ${broadcast:+broadcast} ${broadcast} ${mtu:+mtu} ${mtu}"

		veinfo "ip link add link \"${IFACE}\" name \"${vname}\" ${opts} type vlan id \"${vlan}\" ${vflags} ${vingress} ${vegress}"
		e="$(ip link add link "${IFACE}" name "${vname}" ${opts} type vlan id "${vlan}" ${vflags} ${vingress} ${vegress} 2>&1 1>/dev/null)"
		if [ -n "${e}" ]; then
			eend 1 "${e}"
			continue
		fi

		# We may not want to start the vlan ourselves
		eval s=\$vlan_start_${IFVAR}
		yesno ${s:-yes} || continue

		# We need to work out the interface name of our new vlan id
		local ifname="$(sed -n -e \
			's/^\([^[:space:]]*\) *| '"${vlan}"' *| .*'"${IFACE}"'$/\1/p' \
			/proc/net/vlan/config )"
		mark_service_started "net.${ifname}"
		(
			RC_SVCNAME="net.${ifname}" ; export RC_SVCNAME
			start
		) || mark_service_stopped "net.${ifname}"
	done

	return 0
}

vlan_pre_stop()
{
	local vlan=

	_exists || return 0

	for vlan in $(_get_vlans); do
		einfo "Removing VLAN ${vlan##*.} from ${IFACE}"
		(
			RC_SVCNAME="net.${vlan}" ; export RC_SVCNAME
			stop
		) && {
			mark_service_stopped "net.${vlan}"
			ip link delete "${vlan}" type vlan >/dev/null
		}
	done

	return 0
}