procd: update to git HEAD
[openwrt/staging/noltari.git] / package / network / config / vfconfig / files / vfconfig.sh
1 #!/bin/sh
2
3 . /lib/functions.sh
4 . /lib/functions/network.sh
5
6 bridge_names=""
7
8 warn() {
9 echo "$@" >&2
10 }
11
12 clear_port_vlans() {
13 local port=$1
14 local self=$2
15 local vlans=$(bridge vlan show dev "$port" | sed -ne 's#^[^ ]* \+\([0-9]\+\).*$#\1#p')
16
17 local vlan
18 for vlan in $vlans; do
19 bridge vlan del vid "$vlan" dev "$port" $self
20 done
21 }
22
23 add_bridge() {
24 local cfg=$1
25 local brname
26
27 config_get brname "$cfg" bridge "switch0"
28
29 case " $bridge_names " in
30 *" $brname "*) return 1 ;;
31 esac
32
33 append bridge_names "$brname"
34
35 export -n "bridge=$brname"
36 }
37
38 validate_vid() {
39 local vid=$1
40
41 case "$vid" in
42 [1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-4][0-9][0-9][0-9])
43 if [ $vid -gt 4096 ]; then
44 return 1
45 fi
46 ;;
47 *)
48 return 1
49 ;;
50 esac
51
52 return 0
53 }
54
55 setup_bridge() {
56 local cfg=$1
57 local bridge
58
59 add_bridge "$cfg" || return 0
60
61 # Prevent netifd from picking up our switch bridge just yet
62 network_defer_device "$bridge"
63
64 # (Re)create switch bridge device in case it is not yet set up
65 local filtering=$(cat "/sys/class/net/$bridge/bridge/vlan_filtering" 2>/dev/null)
66 if [ ${filtering:-0} != 1 ]; then
67 ip link set "$bridge" down 2>/dev/null
68 ip link delete dev "$bridge" 2>/dev/null
69 ip link add name "$bridge" type bridge
70 echo 1 > "/sys/class/net/$bridge/bridge/vlan_filtering"
71 fi
72
73 ip link set "$bridge" up
74
75 # Unbridge DSA ports and flush any VLAN filters on them, they're added back later
76 local port
77 for port in /sys/class/net/*"/upper_${cfg}"; do
78 if [ -e "$port" ]; then
79 port=${port%/upper_*}
80 port=${port##*/}
81
82 ip link set "$port" nomaster
83
84 # Unbridging the port should already clear VLANs, but be safe
85 clear_port_vlans "$port"
86 fi
87 done
88
89 # Clear any VLANs on the switch bridge, they're added back later
90 clear_port_vlans "$bridge" self
91 }
92
93 setup_bridge_vlan() {
94 local cfg=$1
95 local bridge vlan ports
96
97 config_get bridge "$cfg" bridge "switch0"
98 config_get vlan "$cfg" vlan
99 config_get ports "$cfg" ports
100
101 validate_vid "$vlan" || {
102 warn "VLAN section '$cfg' specifies an invalid VLAN ID '$vlan'"
103 return 1
104 }
105
106 # Setup ports
107 local port tag pvid
108 for port in $ports; do
109 tag=untagged
110 pvid=
111
112 case "$port" in
113 *"*")
114 pvid=pvid
115 port=${port%\*}
116 ;;
117 esac
118
119 case "$port" in
120 *:u)
121 port=${port%:u}
122 ;;
123 *:t)
124 tag=tagged
125 port=${port%:t}
126 ;;
127 esac
128
129 # Add the port to the switch bridge and delete the default
130 # VLAN 1 if it is not yet joined to the bridge.
131 if [ ! -e "/sys/class/net/$port/upper_$bridge" ]; then
132 ip link set dev "$port" up
133 ip link set dev "$port" master "$bridge"
134
135 # Get rid of default VLAN 1
136 bridge vlan del vid 1 dev "$port"
137 fi
138
139 # Promote the first untagged VLAN of this port to the PVID
140 if [ "$tag" = untagged ] && ! bridge vlan show dev "$port" | grep -qi pvid; then
141 pvid=pvid
142 fi
143
144 # Add VLAN filter entry for port
145 bridge vlan add dev "$port" vid $vlan $pvid $tag
146 done
147
148 # Make the switch bridge itself handle the VLAN as well
149 bridge vlan add dev "$bridge" self vid $vlan tagged
150 }
151
152 apply_config() {
153 config_load network
154 config_foreach setup_bridge vlan_filter
155 config_foreach setup_bridge_vlan vlan_filter
156
157 # Ready switch bridge devices
158 local bridge
159 for bridge in $bridge_names; do
160 network_ready_device "$bridge"
161 done
162 }
163
164 show_bridge() {
165 local cfg=$1
166 local bridge
167
168 add_bridge "$cfg" || return 0
169
170 printf "Bridge: %s\n" "$bridge"
171 printf "VLAN/"
172
173 local port ports
174 for port in "/sys/class/net/$bridge/lower_"*; do
175 [ -e "$port" ] || continue
176
177 port=${port##*/lower_}
178
179 printf " | %-5s" "$port"
180 append ports "$port"
181 done
182
183 printf " |\nLink:"
184
185 for port in $ports; do
186 local carrier=$(cat "/sys/class/net/$port/carrier")
187 local duplex=$(cat "/sys/class/net/$port/duplex")
188 local speed=$(cat "/sys/class/net/$port/speed")
189
190 if [ ${carrier:-0} -eq 0 ]; then
191 printf " | %-5s" "down"
192 else
193 [ "$duplex" = "full" ] && duplex=F || duplex=H
194 printf " | %4d%s" "$speed" "$duplex"
195 fi
196 done
197
198 local vlans=$(bridge vlan show dev "$bridge" | sed -ne 's#^[^ ]* \+\([0-9]\+\).*$#\1#p')
199 local vlan
200 for vlan in $vlans; do
201 printf " |\n%4d " "$vlan"
202
203 for port in $ports; do
204 local pvid="" utag="" word
205 for word in $(bridge vlan show dev "$port" vid "$vlan"); do
206 case "$word" in
207 PVID) pvid="*" ;;
208 "$vlan") utag="t" ;;
209 Untagged) utag="u" ;;
210 esac
211 done
212
213 printf " | %-2s " "$utag$pvid"
214 done
215 done
216
217 printf " |\n\n"
218 }
219
220 show_config() {
221 config_load network
222 config_foreach show_bridge vlan_filter
223 }
224
225
226 case "$1" in
227 show) show_config ;;
228 apply) apply_config ;;
229 *)
230 echo "Usage: ${0##*/} show"
231 echo " ${0##*/} apply"
232 exit 1
233 ;;
234 esac