summaryrefslogtreecommitdiff
path: root/proto/radv/config.Y
blob: f40fdcca0f04210ed47717fd3ab438e6c23a94a0 (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/*
 *	BIRD -- Router Advertisement Configuration
 *
 *	(c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
 *	(c) 2011--2019 CZ.NIC z.s.p.o.
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

CF_HDR

#include "proto/radv/radv.h"

CF_DEFINES

#define RADV_CFG ((struct radv_config *) this_proto)
#define RADV_IFACE ((struct radv_iface_config *) this_ipatt)
#define RADV_PREFIX this_radv_prefix
#define RADV_RDNSS (&this_radv_rdnss)
#define RADV_DNSSL (&this_radv_dnssl)

static struct radv_prefix_config *this_radv_prefix;
static struct radv_rdnss_config this_radv_rdnss;
static struct radv_dnssl_config this_radv_dnssl;
static list radv_dns_list;	/* Used by radv_rdnss and radv_dnssl */
static u8 radv_mult_val;	/* Used by radv_mult for second return value */


CF_DECLS

CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, SOLICITED,
	UNICAST, MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME,
	RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
	LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LOCAL,
	TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, ROUTE,
	ROUTES, RA_PREFERENCE, RA_LIFETIME)

CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)

%type<i> radv_mult radv_sensitive radv_preference

CF_GRAMMAR

proto: radv_proto ;

radv_proto_start: proto_start RADV
{
  this_proto = proto_config_new(&proto_radv, $1);
  this_proto->net_type = NET_IP6;

  init_list(&RADV_CFG->patt_list);
  init_list(&RADV_CFG->pref_list);
  init_list(&RADV_CFG->rdnss_list);
  init_list(&RADV_CFG->dnssl_list);
};

radv_proto_item:
   proto_item
 | proto_channel
 | INTERFACE radv_iface
 | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
 | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
 | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
 | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
 | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
 ;

radv_proto_opts:
   /* empty */
 | radv_proto_opts radv_proto_item ';'
 ;

radv_proto:
   radv_proto_start proto_name '{' radv_proto_opts '}';


radv_iface_start:
{
  this_ipatt = cfg_allocz(sizeof(struct radv_iface_config));
  add_tail(&RADV_CFG->patt_list, NODE this_ipatt);
  init_list(&this_ipatt->ipn_list);
  init_list(&RADV_IFACE->pref_list);
  init_list(&RADV_IFACE->rdnss_list);
  init_list(&RADV_IFACE->dnssl_list);

  RADV_IFACE->min_ra_int = (u32) -1; /* undefined */
  RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
  RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
  RADV_IFACE->prefix_linger_time = (u32) -1;
  RADV_IFACE->route_linger_time = (u32) -1;
  RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
  RADV_IFACE->default_lifetime = (u32) -1;
  RADV_IFACE->default_lifetime_sensitive = 1;
  RADV_IFACE->default_preference = RA_PREF_MEDIUM;
  RADV_IFACE->route_lifetime = (u32) -1;
  RADV_IFACE->route_lifetime_sensitive = 0;
  RADV_IFACE->route_preference = RA_PREF_MEDIUM;
};

radv_iface_item:
   MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); }
 | 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"); }
 | MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
 | SOLICITED RA UNICAST bool { RADV_IFACE->solicited_ra_unicast = $4; }
 | MANAGED bool { RADV_IFACE->managed = $2; }
 | OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
 | LINK MTU expr { RADV_IFACE->link_mtu = $3; }
 | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); }
 | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; }
 | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); }
 | DEFAULT LIFETIME expr radv_sensitive {
     RADV_IFACE->default_lifetime = $3;
     if ($3 > 9000)  cf_error("Default lifetime must be in range 0-9000");
     if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4;
   }
 | ROUTE LIFETIME expr radv_sensitive {
     RADV_IFACE->route_lifetime = $3;
     if ($4 != (uint) -1) RADV_IFACE->route_lifetime_sensitive = $4;
   }
 | DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; }
 | ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; }
 | PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; }
 | ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; }
 | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
 | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
 | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
 | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
 | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
 ;

radv_preference:
   LOW { $$ = RA_PREF_LOW; }
 | MEDIUM { $$ = RA_PREF_MEDIUM; }
 | HIGH { $$ = RA_PREF_HIGH; }

radv_iface_finish:
{
  struct radv_iface_config *ic = RADV_IFACE;

  if (ic->min_ra_int == (u32) -1)
    ic->min_ra_int = MAX_(ic->max_ra_int / 3, 3);

  if (ic->default_lifetime == (u32) -1)
    ic->default_lifetime = 3 * ic->max_ra_int;

  if (ic->route_lifetime == (u32) -1)
    ic->route_lifetime = 3 * ic->max_ra_int;

  if (ic->prefix_linger_time == (u32) -1)
    ic->prefix_linger_time = 3 * ic->max_ra_int;

  if (ic->route_linger_time == (u32) -1)
    ic->route_linger_time = 3 * ic->max_ra_int;

  if ((ic->min_ra_int > 3) &&
      (ic->min_ra_int > (ic->max_ra_int * 3 / 4)))
    cf_error("Min RA interval must be at most 3/4 * Max RA interval");

  if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int))
    cf_error("Default lifetime must be either 0 or at least Max RA interval");

  if ((ic->route_lifetime > 0) && (ic->route_lifetime < ic->max_ra_int))
    cf_error("Route lifetime must be either 0 or at least Max RA interval");

  if ((ic->prefix_linger_time > 0) && (ic->prefix_linger_time < ic->max_ra_int))
    cf_error("Prefix linger time must be either 0 or at least Max RA interval");

  if ((ic->route_linger_time > 0) && (ic->route_linger_time < ic->max_ra_int))
    cf_error("Route linger time must be either 0 or at least Max RA interval");

  RADV_CFG->max_linger_time = MAX_(RADV_CFG->max_linger_time, ic->route_linger_time);
};


radv_iface_opts:
   /* empty */
 | radv_iface_opts radv_iface_item ';'
 ;

radv_iface_opt_list:
   /* empty */
 | '{' radv_iface_opts '}'
 ;

radv_iface:
  radv_iface_start iface_patt_list_nopx radv_iface_opt_list radv_iface_finish;


radv_prefix_start: net_ip6
{
  this_radv_prefix = cfg_allocz(sizeof(struct radv_prefix_config));
  RADV_PREFIX->prefix = *(net_addr_ip6 *) &($1);

  RADV_PREFIX->onlink = 1;
  RADV_PREFIX->autonomous = 1;
  RADV_PREFIX->valid_lifetime = DEFAULT_VALID_LIFETIME;
  RADV_PREFIX->preferred_lifetime = DEFAULT_PREFERRED_LIFETIME;
};

radv_prefix_item:
   SKIP bool { RADV_PREFIX->skip = $2; }
 | ONLINK bool { RADV_PREFIX->onlink = $2; }
 | AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; }
 | VALID LIFETIME expr radv_sensitive {
     RADV_PREFIX->valid_lifetime = $3;
     if ($4 != (uint) -1) RADV_PREFIX->valid_lifetime_sensitive = $4;
   }
 | PREFERRED LIFETIME expr radv_sensitive {
     RADV_PREFIX->preferred_lifetime = $3;
     if ($4 != (uint) -1) RADV_PREFIX->preferred_lifetime_sensitive = $4;
   }
 ;

radv_prefix_finish:
{
  if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->valid_lifetime)
    cf_error("Preferred lifetime must be at most Valid lifetime");

  if (RADV_PREFIX->valid_lifetime_sensitive > RADV_PREFIX->preferred_lifetime_sensitive)
    cf_error("Valid lifetime sensitive requires that Preferred lifetime is sensitive too");
};

radv_prefix_opts:
   /* empty */
 | radv_prefix_opts radv_prefix_item ';'
 ;

radv_prefix_opt_list:
   /* empty */
 | '{' radv_prefix_opts '}'
 ;

radv_prefix:
  radv_prefix_start radv_prefix_opt_list radv_prefix_finish;



radv_rdnss_node: ipa
{
  struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config));
  add_tail(&radv_dns_list, NODE cf);

  cf->server = $1;
  cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
};

radv_rdnss_start:
{
  RADV_RDNSS->lifetime = 0;
  RADV_RDNSS->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
};

radv_rdnss_item:
 | NS radv_rdnss_node
 | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; }
 ;

radv_rdnss_finish:
{
  if (EMPTY_LIST(radv_dns_list))
    cf_error("No nameserver in RDNSS section");

  struct radv_rdnss_config *cf;
  WALK_LIST(cf, radv_dns_list)
  {
    cf->lifetime = RADV_RDNSS->lifetime;
    cf->lifetime_mult = RADV_RDNSS->lifetime_mult;
  }
};

radv_rdnss_opts:
   /* empty */
 | radv_rdnss_opts radv_rdnss_item ';'
 ;

radv_rdnss:
   radv_rdnss_node
 | '{' radv_rdnss_start radv_rdnss_opts '}' radv_rdnss_finish
 ;


radv_dnssl_node: TEXT
{
  struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config));
  add_tail(&radv_dns_list, NODE cf);

  cf->domain = $1;
  cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;

  if (radv_process_domain(cf) < 0)
    cf_error("Invalid domain dame");
};

radv_dnssl_start:
{
  RADV_DNSSL->lifetime = 0;
  RADV_DNSSL->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
};

radv_dnssl_item:
 | DOMAIN radv_dnssl_node
 | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; }
 ;

radv_dnssl_finish:
{
  if (EMPTY_LIST(radv_dns_list))
    cf_error("No domain in DNSSL section");

  struct radv_dnssl_config *cf;
  WALK_LIST(cf, radv_dns_list)
  {
    cf->lifetime = RADV_DNSSL->lifetime;
    cf->lifetime_mult = RADV_DNSSL->lifetime_mult;
  }
};

radv_dnssl_opts:
   /* empty */
 | radv_dnssl_opts radv_dnssl_item ';'
 ;

radv_dnssl:
   radv_dnssl_node
 | '{' radv_dnssl_start radv_dnssl_opts '}' radv_dnssl_finish
 ;


radv_mult:
   expr { $$ = $1; radv_mult_val = 0; }
 | MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); }
 ;

radv_sensitive:
   /* empty */ { $$ = (uint) -1; }
 | SENSITIVE bool { $$ = $2; }
 ;

CF_CODE

CF_END