proto-shell: add helpers for generic options in proto handlers
[project/netifd.git] / scripts / netifd-proto.sh
1 NETIFD_MAIN_DIR="${NETIFD_MAIN_DIR:-/lib/netifd}"
2 PROTO_DEFAULT_OPTIONS="defaultroute peerdns metric"
3
4 . /usr/share/libubox/jshn.sh
5 . $NETIFD_MAIN_DIR/utils.sh
6
7 proto_config_add_int() {
8 config_add_int "$@"
9 }
10
11 proto_config_add_string() {
12 config_add_string "$@"
13 }
14
15 proto_config_add_boolean() {
16 config_add_boolean "$@"
17 }
18
19 proto_config_add_defaults() {
20 proto_config_add_boolean "defaultroute"
21 proto_config_add_boolean "peerdns"
22 proto_config_add_int "metric"
23 }
24
25 proto_add_dynamic_defaults() {
26 [ -n "$defaultroute" ] && json_add_boolean defaultroute "$defaultroute"
27 [ -n "$peerdns" ] && json_add_boolean peerdns "$peerdns"
28 [ -n "$metric" ] && json_add_int metric "$metric"
29 }
30
31 _proto_do_teardown() {
32 json_load "$data"
33 eval "proto_$1_teardown \"$interface\" \"$ifname\""
34 }
35
36 _proto_do_renew() {
37 json_load "$data"
38 eval "proto_$1_renew \"$interface\" \"$ifname\""
39 }
40
41 _proto_do_setup() {
42 json_load "$data"
43 _EXPORT_VAR=0
44 _EXPORT_VARS=
45 eval "proto_$1_setup \"$interface\" \"$ifname\""
46 }
47
48 proto_init_update() {
49 local ifname="$1"
50 local up="$2"
51 local external="$3"
52
53 PROTO_KEEP=0
54 PROTO_INIT=1
55 PROTO_TUNNEL_OPEN=
56 PROTO_IPADDR=
57 PROTO_IP6ADDR=
58 PROTO_ROUTE=
59 PROTO_ROUTE6=
60 PROTO_PREFIX6=
61 PROTO_DNS=
62 PROTO_DNS_SEARCH=
63 json_init
64 json_add_int action 0
65 [ -n "$ifname" -a "*" != "$ifname" ] && json_add_string "ifname" "$ifname"
66 json_add_boolean "link-up" "$up"
67 [ -n "$3" ] && json_add_boolean "address-external" "$external"
68 }
69
70 proto_set_keep() {
71 PROTO_KEEP="$1"
72 }
73
74 proto_close_nested() {
75 [ -n "$PROTO_NESTED_OPEN" ] && json_close_object
76 PROTO_NESTED_OPEN=
77 }
78
79 proto_add_nested() {
80 PROTO_NESTED_OPEN=1
81 json_add_object "$1"
82 }
83
84 proto_add_tunnel() {
85 proto_add_nested "tunnel"
86 }
87
88 proto_close_tunnel() {
89 proto_close_nested
90 }
91
92 proto_add_data() {
93 proto_add_nested "data"
94 }
95
96 proto_close_data() {
97 proto_close_nested
98 }
99
100 proto_add_dns_server() {
101 local address="$1"
102
103 append PROTO_DNS "$address"
104 }
105
106 proto_add_dns_search() {
107 local address="$1"
108
109 append PROTO_DNS_SEARCH "$address"
110 }
111
112 proto_add_ipv4_address() {
113 local address="$1"
114 local mask="$2"
115 local broadcast="$3"
116 local ptp="$4"
117
118 append PROTO_IPADDR "$address/$mask/$broadcast/$ptp"
119 }
120
121 proto_add_ipv6_address() {
122 local address="$1"
123 local mask="$2"
124 local preferred="$3"
125 local valid="$4"
126 local offlink="$5"
127 local class="$6"
128
129 append PROTO_IP6ADDR "$address/$mask/$preferred/$valid/$offlink/$class"
130 }
131
132 proto_add_ipv4_route() {
133 local target="$1"
134 local mask="$2"
135 local gw="$3"
136 local source="$4"
137 local metric="$5"
138
139 append PROTO_ROUTE "$target/$mask/$gw/$metric///$source"
140 }
141
142 proto_add_ipv6_route() {
143 local target="$1"
144 local mask="$2"
145 local gw="$3"
146 local metric="$4"
147 local valid="$5"
148 local source="$6"
149 local table="$7"
150
151 append PROTO_ROUTE6 "$target/$mask/$gw/$metric/$valid/$table/$source"
152 }
153
154 proto_add_ipv6_prefix() {
155 local prefix="$1"
156 local valid="$2"
157 local preferred="$3"
158
159 if [ -z "$valid" ]; then
160 append PROTO_PREFIX6 "$prefix"
161 else
162 [ -z "$preferred" ] && preferred="$valid"
163 append PROTO_PREFIX6 "$prefix,$valid,$preferred"
164 fi
165 }
166
167 _proto_push_ipv4_addr() {
168 local str="$1"
169 local address mask broadcast ptp
170
171 address="${str%%/*}"
172 str="${str#*/}"
173 mask="${str%%/*}"
174 str="${str#*/}"
175 broadcast="${str%%/*}"
176 str="${str#*/}"
177 ptp="$str"
178
179 json_add_object ""
180 json_add_string ipaddr "$address"
181 [ -n "$mask" ] && json_add_string mask "$mask"
182 [ -n "$broadcast" ] && json_add_string broadcast "$broadcast"
183 [ -n "$ptp" ] && json_add_string ptp "$ptp"
184 json_close_object
185 }
186
187 _proto_push_ipv6_addr() {
188 local str="$1"
189 local address mask preferred valid offlink
190
191 address="${str%%/*}"
192 str="${str#*/}"
193 mask="${str%%/*}"
194 str="${str#*/}"
195 preferred="${str%%/*}"
196 str="${str#*/}"
197 valid="${str%%/*}"
198 str="${str#*/}"
199 offlink="${str%%/*}"
200 str="${str#*/}"
201 class="${str%%/*}"
202
203 json_add_object ""
204 json_add_string ipaddr "$address"
205 [ -n "$mask" ] && json_add_string mask "$mask"
206 [ -n "$preferred" ] && json_add_int preferred "$preferred"
207 [ -n "$valid" ] && json_add_int valid "$valid"
208 [ -n "$offlink" ] && json_add_boolean offlink "$offlink"
209 [ -n "$class" ] && json_add_string class "$class"
210 json_close_object
211 }
212
213 _proto_push_string() {
214 json_add_string "" "$1"
215 }
216
217 _proto_push_route() {
218 local str="$1";
219 local target="${str%%/*}"
220 str="${str#*/}"
221 local mask="${str%%/*}"
222 str="${str#*/}"
223 local gw="${str%%/*}"
224 str="${str#*/}"
225 local metric="${str%%/*}"
226 str="${str#*/}"
227 local valid="${str%%/*}"
228 str="${str#*/}"
229 local table="${str%%/*}"
230 str="${str#*/}"
231 local source="${str}"
232
233 json_add_object ""
234 json_add_string target "$target"
235 json_add_string netmask "$mask"
236 [ -n "$gw" ] && json_add_string gateway "$gw"
237 [ -n "$metric" ] && json_add_int metric "$metric"
238 [ -n "$valid" ] && json_add_int valid "$valid"
239 [ -n "$source" ] && json_add_string source "$source"
240 [ -n "$table" ] && json_add_string table "$table"
241 json_close_object
242 }
243
244 _proto_push_array() {
245 local name="$1"
246 local val="$2"
247 local cb="$3"
248
249 [ -n "$val" ] || return 0
250 json_add_array "$name"
251 for item in $val; do
252 eval "$cb \"\$item\""
253 done
254 json_close_array
255 }
256
257 _proto_notify() {
258 local interface="$1"
259 local options="$2"
260 json_add_string "interface" "$interface"
261 ubus $options call network.interface notify_proto "$(json_dump)"
262 }
263
264 proto_send_update() {
265 local interface="$1"
266
267 proto_close_nested
268 json_add_boolean keep "$PROTO_KEEP"
269 _proto_push_array "ipaddr" "$PROTO_IPADDR" _proto_push_ipv4_addr
270 _proto_push_array "ip6addr" "$PROTO_IP6ADDR" _proto_push_ipv6_addr
271 _proto_push_array "routes" "$PROTO_ROUTE" _proto_push_route
272 _proto_push_array "routes6" "$PROTO_ROUTE6" _proto_push_route
273 _proto_push_array "ip6prefix" "$PROTO_PREFIX6" _proto_push_string
274 _proto_push_array "dns" "$PROTO_DNS" _proto_push_string
275 _proto_push_array "dns_search" "$PROTO_DNS_SEARCH" _proto_push_string
276 _proto_notify "$interface"
277 }
278
279 proto_export() {
280 local var="VAR${_EXPORT_VAR}"
281 _EXPORT_VAR="$(($_EXPORT_VAR + 1))"
282 export -- "$var=$1"
283 append _EXPORT_VARS "$var"
284 }
285
286 proto_run_command() {
287 local interface="$1"; shift
288
289 json_init
290 json_add_int action 1
291 json_add_array command
292 while [ $# -gt 0 ]; do
293 json_add_string "" "$1"
294 shift
295 done
296 json_close_array
297 [ -n "$_EXPORT_VARS" ] && {
298 json_add_array env
299 for var in $_EXPORT_VARS; do
300 eval "json_add_string \"\" \"\${$var}\""
301 done
302 json_close_array
303 }
304 _proto_notify "$interface"
305 }
306
307 proto_kill_command() {
308 local interface="$1"; shift
309
310 json_init
311 json_add_int action 2
312 [ -n "$1" ] && json_add_int signal "$1"
313 _proto_notify "$interface"
314 }
315
316 proto_notify_error() {
317 local interface="$1"; shift
318
319 json_init
320 json_add_int action 3
321 json_add_array error
322 while [ $# -gt 0 ]; do
323 json_add_string "" "$1"
324 shift
325 done
326 json_close_array
327 _proto_notify "$interface"
328 }
329
330 proto_block_restart() {
331 local interface="$1"; shift
332
333 json_init
334 json_add_int action 4
335 _proto_notify "$interface"
336 }
337
338 proto_set_available() {
339 local interface="$1"
340 local state="$2"
341 json_init
342 json_add_int action 5
343 json_add_boolean available "$state"
344 _proto_notify "$interface"
345 }
346
347 proto_add_host_dependency() {
348 local interface="$1"
349 local host="$2"
350 local ifname="$3"
351
352 # execute in subshell to not taint callers env
353 # see tickets #11046, #11545, #11570
354 (
355 json_init
356 json_add_int action 6
357 json_add_string host "$host"
358 [ -n "$ifname" ] && json_add_string ifname "$ifname"
359 _proto_notify "$interface" -S
360 )
361 }
362
363 proto_setup_failed() {
364 local interface="$1"
365 json_init
366 json_add_int action 7
367 _proto_notify "$interface"
368 }
369
370 init_proto() {
371 proto="$1"; shift
372 cmd="$1"; shift
373
374 case "$cmd" in
375 dump)
376 add_protocol() {
377 no_device=0
378 no_proto_task=0
379 available=0
380 renew_handler=0
381 teardown_on_l3_link_down=0
382
383 add_default_handler "proto_$1_init_config"
384
385 json_init
386 json_add_string "name" "$1"
387 json_add_array "config"
388 eval "proto_$1_init_config"
389 json_close_array
390 json_add_boolean no-device "$no_device"
391 json_add_boolean no-proto-task "$no_proto_task"
392 json_add_boolean available "$available"
393 json_add_boolean renew-handler "$renew_handler"
394 json_add_boolean lasterror "$lasterror"
395 json_add_boolean teardown-on-l3-link-down "$teardown_on_l3_link_down"
396 json_dump
397 }
398 ;;
399 setup|teardown|renew)
400 interface="$1"; shift
401 data="$1"; shift
402 ifname="$1"; shift
403
404 add_protocol() {
405 [[ "$proto" == "$1" ]] || return 0
406
407 case "$cmd" in
408 setup) _proto_do_setup "$1";;
409 teardown) _proto_do_teardown "$1" ;;
410 renew) _proto_do_renew "$1" ;;
411 *) return 1 ;;
412 esac
413 }
414 ;;
415 esac
416 }