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