]>
Commit | Line | Data |
---|---|---|
93e868c7 OZ |
1 | /* |
2 | * BIRD -- Router Advertisement Configuration | |
3 | * | |
70a4320b OZ |
4 | * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org> |
5 | * (c) 2011--2019 CZ.NIC z.s.p.o. | |
93e868c7 OZ |
6 | * |
7 | * Can be freely distributed and used under the terms of the GNU GPL. | |
8 | */ | |
9 | ||
10 | CF_HDR | |
11 | ||
12 | #include "proto/radv/radv.h" | |
13 | ||
14 | CF_DEFINES | |
15 | ||
16 | #define RADV_CFG ((struct radv_config *) this_proto) | |
17 | #define RADV_IFACE ((struct radv_iface_config *) this_ipatt) | |
18 | #define RADV_PREFIX this_radv_prefix | |
fc06fb62 OZ |
19 | #define RADV_RDNSS (&this_radv_rdnss) |
20 | #define RADV_DNSSL (&this_radv_dnssl) | |
93e868c7 OZ |
21 | |
22 | static struct radv_prefix_config *this_radv_prefix; | |
fc06fb62 OZ |
23 | static struct radv_rdnss_config this_radv_rdnss; |
24 | static struct radv_dnssl_config this_radv_dnssl; | |
25 | static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */ | |
26 | static u8 radv_mult_val; /* Used by radv_mult for second return value */ | |
27 | ||
9c81250c | 28 | static inline void |
fea04d7c | 29 | radv_add_to_custom_list(list *l, int type, const struct bytestring *payload) |
9c81250c AZ |
30 | { |
31 | if (type < 0 || type > 255) cf_error("RA cusom type must be in range 0-255"); | |
32 | struct radv_custom_config *cf = cfg_allocz(sizeof(struct radv_custom_config)); | |
33 | add_tail(l, NODE cf); | |
34 | cf->type = type; | |
35 | cf->payload = payload; | |
36 | } | |
93e868c7 OZ |
37 | |
38 | CF_DECLS | |
39 | ||
70a4320b OZ |
40 | CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, SOLICITED, |
41 | UNICAST, MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, | |
42 | RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, | |
43 | LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LOCAL, | |
44 | TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, ROUTE, | |
ccfa48a2 | 45 | ROUTES, RA_PREFERENCE, RA_LIFETIME, CUSTOM, OPTION, TYPE, VALUE) |
2a95e633 MV |
46 | |
47 | CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH) | |
93e868c7 | 48 | |
75148289 | 49 | %type<i> radv_mult radv_sensitive radv_preference |
93e868c7 OZ |
50 | |
51 | CF_GRAMMAR | |
52 | ||
f851f0d7 | 53 | proto: radv_proto ; |
93e868c7 OZ |
54 | |
55 | radv_proto_start: proto_start RADV | |
56 | { | |
2bbc3083 | 57 | this_proto = proto_config_new(&proto_radv, $1); |
f761be6b | 58 | this_proto->net_type = NET_IP6; |
f4a60a9b | 59 | |
93e868c7 OZ |
60 | init_list(&RADV_CFG->patt_list); |
61 | init_list(&RADV_CFG->pref_list); | |
fc06fb62 OZ |
62 | init_list(&RADV_CFG->rdnss_list); |
63 | init_list(&RADV_CFG->dnssl_list); | |
9c81250c | 64 | init_list(&RADV_CFG->custom_list); |
93e868c7 OZ |
65 | }; |
66 | ||
67 | radv_proto_item: | |
68 | proto_item | |
f4a60a9b | 69 | | proto_channel |
93e868c7 | 70 | | INTERFACE radv_iface |
fc06fb62 OZ |
71 | | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); } |
72 | | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } | |
73 | | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } | |
f411a19b | 74 | | CUSTOM OPTION TYPE expr VALUE bytestring { radv_add_to_custom_list(&RADV_CFG->custom_list, $4, $6); } |
f4a60a9b | 75 | | TRIGGER net_ip6 { RADV_CFG->trigger = $2; } |
2a95e633 | 76 | | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; } |
93e868c7 OZ |
77 | ; |
78 | ||
79 | radv_proto_opts: | |
80 | /* empty */ | |
81 | | radv_proto_opts radv_proto_item ';' | |
82 | ; | |
83 | ||
84 | radv_proto: | |
fc06fb62 | 85 | radv_proto_start proto_name '{' radv_proto_opts '}'; |
93e868c7 OZ |
86 | |
87 | ||
88 | radv_iface_start: | |
89 | { | |
90 | this_ipatt = cfg_allocz(sizeof(struct radv_iface_config)); | |
91 | add_tail(&RADV_CFG->patt_list, NODE this_ipatt); | |
92 | init_list(&this_ipatt->ipn_list); | |
93 | init_list(&RADV_IFACE->pref_list); | |
fc06fb62 OZ |
94 | init_list(&RADV_IFACE->rdnss_list); |
95 | init_list(&RADV_IFACE->dnssl_list); | |
9c81250c | 96 | init_list(&RADV_IFACE->custom_list); |
93e868c7 | 97 | |
830ba75e | 98 | RADV_IFACE->min_ra_int = (u32) -1; /* undefined */ |
93e868c7 OZ |
99 | RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT; |
100 | RADV_IFACE->min_delay = DEFAULT_MIN_DELAY; | |
830ba75e OZ |
101 | RADV_IFACE->prefix_linger_time = (u32) -1; |
102 | RADV_IFACE->route_linger_time = (u32) -1; | |
93e868c7 | 103 | RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT; |
830ba75e | 104 | RADV_IFACE->default_lifetime = (u32) -1; |
36da2857 | 105 | RADV_IFACE->default_lifetime_sensitive = 1; |
75148289 | 106 | RADV_IFACE->default_preference = RA_PREF_MEDIUM; |
830ba75e | 107 | RADV_IFACE->route_lifetime = (u32) -1; |
7c0bab3a OZ |
108 | RADV_IFACE->route_lifetime_sensitive = 0; |
109 | RADV_IFACE->route_preference = RA_PREF_MEDIUM; | |
93e868c7 OZ |
110 | }; |
111 | ||
112 | radv_iface_item: | |
113 | MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); } | |
114 | | MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error("Max RA interval must be in range 4-1800"); } | |
115 | | MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); } | |
70a4320b | 116 | | SOLICITED RA UNICAST bool { RADV_IFACE->solicited_ra_unicast = $4; } |
93e868c7 OZ |
117 | | MANAGED bool { RADV_IFACE->managed = $2; } |
118 | | OTHER CONFIG bool { RADV_IFACE->other_config = $3; } | |
6aaaa635 OZ |
119 | | LINK MTU expr { RADV_IFACE->link_mtu = $3; } |
120 | | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); } | |
121 | | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; } | |
122 | | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); } | |
36da2857 OZ |
123 | | DEFAULT LIFETIME expr radv_sensitive { |
124 | RADV_IFACE->default_lifetime = $3; | |
6aaaa635 OZ |
125 | if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000"); |
126 | if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4; | |
36da2857 | 127 | } |
7c0bab3a OZ |
128 | | ROUTE LIFETIME expr radv_sensitive { |
129 | RADV_IFACE->route_lifetime = $3; | |
830ba75e | 130 | if ($4 != (uint) -1) RADV_IFACE->route_lifetime_sensitive = $4; |
7c0bab3a | 131 | } |
75148289 | 132 | | DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; } |
7c0bab3a OZ |
133 | | ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; } |
134 | | PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; } | |
135 | | ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; } | |
93e868c7 | 136 | | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } |
fc06fb62 OZ |
137 | | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } |
138 | | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } | |
f411a19b | 139 | | CUSTOM OPTION TYPE expr VALUE bytestring { radv_add_to_custom_list(&RADV_IFACE->custom_list, $4, $6); } |
fc06fb62 OZ |
140 | | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; } |
141 | | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; } | |
ccfa48a2 | 142 | | CUSTOM OPTION LOCAL bool { RADV_IFACE->custom_local = $4; } |
93e868c7 OZ |
143 | ; |
144 | ||
75148289 OZ |
145 | radv_preference: |
146 | LOW { $$ = RA_PREF_LOW; } | |
147 | | MEDIUM { $$ = RA_PREF_MEDIUM; } | |
148 | | HIGH { $$ = RA_PREF_HIGH; } | |
149 | ||
93e868c7 OZ |
150 | radv_iface_finish: |
151 | { | |
152 | struct radv_iface_config *ic = RADV_IFACE; | |
153 | ||
154 | if (ic->min_ra_int == (u32) -1) | |
41f8bf57 | 155 | ic->min_ra_int = MAX_(ic->max_ra_int / 3, 3); |
93e868c7 OZ |
156 | |
157 | if (ic->default_lifetime == (u32) -1) | |
158 | ic->default_lifetime = 3 * ic->max_ra_int; | |
159 | ||
7c0bab3a OZ |
160 | if (ic->route_lifetime == (u32) -1) |
161 | ic->route_lifetime = 3 * ic->max_ra_int; | |
162 | ||
163 | if (ic->prefix_linger_time == (u32) -1) | |
164 | ic->prefix_linger_time = 3 * ic->max_ra_int; | |
165 | ||
166 | if (ic->route_linger_time == (u32) -1) | |
167 | ic->route_linger_time = 3 * ic->max_ra_int; | |
168 | ||
93e868c7 OZ |
169 | if ((ic->min_ra_int > 3) && |
170 | (ic->min_ra_int > (ic->max_ra_int * 3 / 4))) | |
6aaaa635 | 171 | cf_error("Min RA interval must be at most 3/4 * Max RA interval"); |
93e868c7 OZ |
172 | |
173 | if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int)) | |
174 | cf_error("Default lifetime must be either 0 or at least Max RA interval"); | |
7c0bab3a OZ |
175 | |
176 | if ((ic->route_lifetime > 0) && (ic->route_lifetime < ic->max_ra_int)) | |
177 | cf_error("Route lifetime must be either 0 or at least Max RA interval"); | |
178 | ||
179 | if ((ic->prefix_linger_time > 0) && (ic->prefix_linger_time < ic->max_ra_int)) | |
180 | cf_error("Prefix linger time must be either 0 or at least Max RA interval"); | |
181 | ||
182 | if ((ic->route_linger_time > 0) && (ic->route_linger_time < ic->max_ra_int)) | |
183 | cf_error("Route linger time must be either 0 or at least Max RA interval"); | |
184 | ||
185 | RADV_CFG->max_linger_time = MAX_(RADV_CFG->max_linger_time, ic->route_linger_time); | |
93e868c7 OZ |
186 | }; |
187 | ||
188 | ||
189 | radv_iface_opts: | |
190 | /* empty */ | |
191 | | radv_iface_opts radv_iface_item ';' | |
192 | ; | |
193 | ||
194 | radv_iface_opt_list: | |
195 | /* empty */ | |
196 | | '{' radv_iface_opts '}' | |
197 | ; | |
198 | ||
199 | radv_iface: | |
d7c06285 | 200 | radv_iface_start iface_patt_list_nopx radv_iface_opt_list radv_iface_finish; |
93e868c7 OZ |
201 | |
202 | ||
d44e686e | 203 | radv_prefix_start: net_ip6 |
93e868c7 OZ |
204 | { |
205 | this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config)); | |
04632fd7 | 206 | RADV_PREFIX->prefix = *(net_addr_ip6 *) &($1); |
93e868c7 OZ |
207 | |
208 | RADV_PREFIX->onlink = 1; | |
209 | RADV_PREFIX->autonomous = 1; | |
210 | RADV_PREFIX->valid_lifetime = DEFAULT_VALID_LIFETIME; | |
211 | RADV_PREFIX->preferred_lifetime = DEFAULT_PREFERRED_LIFETIME; | |
212 | }; | |
213 | ||
214 | radv_prefix_item: | |
215 | SKIP bool { RADV_PREFIX->skip = $2; } | |
216 | | ONLINK bool { RADV_PREFIX->onlink = $2; } | |
217 | | AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; } | |
36da2857 OZ |
218 | | VALID LIFETIME expr radv_sensitive { |
219 | RADV_PREFIX->valid_lifetime = $3; | |
6aaaa635 | 220 | if ($4 != (uint) -1) RADV_PREFIX->valid_lifetime_sensitive = $4; |
36da2857 OZ |
221 | } |
222 | | PREFERRED LIFETIME expr radv_sensitive { | |
223 | RADV_PREFIX->preferred_lifetime = $3; | |
6aaaa635 | 224 | if ($4 != (uint) -1) RADV_PREFIX->preferred_lifetime_sensitive = $4; |
36da2857 | 225 | } |
93e868c7 OZ |
226 | ; |
227 | ||
228 | radv_prefix_finish: | |
229 | { | |
230 | if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->valid_lifetime) | |
231 | cf_error("Preferred lifetime must be at most Valid lifetime"); | |
36da2857 OZ |
232 | |
233 | if (RADV_PREFIX->valid_lifetime_sensitive > RADV_PREFIX->preferred_lifetime_sensitive) | |
234 | cf_error("Valid lifetime sensitive requires that Preferred lifetime is sensitive too"); | |
93e868c7 OZ |
235 | }; |
236 | ||
237 | radv_prefix_opts: | |
238 | /* empty */ | |
239 | | radv_prefix_opts radv_prefix_item ';' | |
240 | ; | |
241 | ||
242 | radv_prefix_opt_list: | |
243 | /* empty */ | |
244 | | '{' radv_prefix_opts '}' | |
245 | ; | |
246 | ||
247 | radv_prefix: | |
248 | radv_prefix_start radv_prefix_opt_list radv_prefix_finish; | |
249 | ||
250 | ||
fc06fb62 OZ |
251 | |
252 | radv_rdnss_node: ipa | |
253 | { | |
254 | struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config)); | |
255 | add_tail(&radv_dns_list, NODE cf); | |
256 | ||
257 | cf->server = $1; | |
258 | cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; | |
259 | }; | |
260 | ||
261 | radv_rdnss_start: | |
262 | { | |
263 | RADV_RDNSS->lifetime = 0; | |
264 | RADV_RDNSS->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; | |
265 | }; | |
266 | ||
267 | radv_rdnss_item: | |
268 | | NS radv_rdnss_node | |
269 | | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; } | |
270 | ; | |
271 | ||
272 | radv_rdnss_finish: | |
273 | { | |
274 | if (EMPTY_LIST(radv_dns_list)) | |
275 | cf_error("No nameserver in RDNSS section"); | |
276 | ||
277 | struct radv_rdnss_config *cf; | |
278 | WALK_LIST(cf, radv_dns_list) | |
279 | { | |
280 | cf->lifetime = RADV_RDNSS->lifetime; | |
281 | cf->lifetime_mult = RADV_RDNSS->lifetime_mult; | |
282 | } | |
283 | }; | |
284 | ||
285 | radv_rdnss_opts: | |
286 | /* empty */ | |
287 | | radv_rdnss_opts radv_rdnss_item ';' | |
288 | ; | |
289 | ||
290 | radv_rdnss: | |
291 | radv_rdnss_node | |
292 | | '{' radv_rdnss_start radv_rdnss_opts '}' radv_rdnss_finish | |
293 | ; | |
294 | ||
295 | ||
296 | radv_dnssl_node: TEXT | |
297 | { | |
298 | struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config)); | |
299 | add_tail(&radv_dns_list, NODE cf); | |
300 | ||
301 | cf->domain = $1; | |
302 | cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; | |
303 | ||
304 | if (radv_process_domain(cf) < 0) | |
305 | cf_error("Invalid domain dame"); | |
306 | }; | |
307 | ||
308 | radv_dnssl_start: | |
309 | { | |
310 | RADV_DNSSL->lifetime = 0; | |
311 | RADV_DNSSL->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT; | |
312 | }; | |
313 | ||
314 | radv_dnssl_item: | |
315 | | DOMAIN radv_dnssl_node | |
316 | | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; } | |
317 | ; | |
318 | ||
319 | radv_dnssl_finish: | |
320 | { | |
321 | if (EMPTY_LIST(radv_dns_list)) | |
322 | cf_error("No domain in DNSSL section"); | |
323 | ||
324 | struct radv_dnssl_config *cf; | |
325 | WALK_LIST(cf, radv_dns_list) | |
326 | { | |
327 | cf->lifetime = RADV_DNSSL->lifetime; | |
328 | cf->lifetime_mult = RADV_DNSSL->lifetime_mult; | |
329 | } | |
330 | }; | |
331 | ||
332 | radv_dnssl_opts: | |
333 | /* empty */ | |
334 | | radv_dnssl_opts radv_dnssl_item ';' | |
335 | ; | |
336 | ||
337 | radv_dnssl: | |
338 | radv_dnssl_node | |
339 | | '{' radv_dnssl_start radv_dnssl_opts '}' radv_dnssl_finish | |
340 | ; | |
341 | ||
342 | ||
343 | radv_mult: | |
344 | expr { $$ = $1; radv_mult_val = 0; } | |
345 | | MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); } | |
346 | ; | |
347 | ||
36da2857 | 348 | radv_sensitive: |
830ba75e | 349 | /* empty */ { $$ = (uint) -1; } |
155134f3 | 350 | | SENSITIVE bool { $$ = $2; } |
36da2857 OZ |
351 | ; |
352 | ||
f851f0d7 JMM |
353 | dynamic_attr: RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } ; |
354 | dynamic_attr: RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } ; | |
2a95e633 | 355 | |
93e868c7 OZ |
356 | CF_CODE |
357 | ||
358 | CF_END |