Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / obj / conf / cf-parse.y @ 2b5ca73a

History | View | Annotate | Download (126 KB)

1
%{
2
/* Headers from conf/confbase.Y */
3

    
4
#define PARSER 1
5

    
6
#include "nest/bird.h"
7
#include "conf/conf.h"
8
#include "lib/resource.h"
9
#include "lib/socket.h"
10
#include "lib/timer.h"
11
#include "lib/string.h"
12
#include "nest/protocol.h"
13
#include "nest/iface.h"
14
#include "nest/route.h"
15
#include "nest/cli.h"
16
#include "filter/filter.h"
17

    
18
/* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */
19

    
20
/* Defines from conf/confbase.Y */
21

    
22
static void
23
check_u16(uint val)
24
{
25
  if (val > 0xFFFF)
26
    cf_error("Value %u out of range (0-65535)", val);
27
}
28

    
29
/* Headers from conf/flowspec.Y */
30

    
31
#define PARSER 1
32

    
33
#include "nest/bird.h"
34
#include "lib/flowspec.h"
35

    
36

    
37
/* Defines from conf/flowspec.Y */
38

    
39
struct flow_builder *this_flow;
40

    
41

    
42
/* Headers from filter/config.Y */
43

    
44
/* Defines from filter/config.Y */
45

    
46
#define P(a,b) ((a << 8) | b)
47

    
48
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
49
static inline u32 pair_a(u32 p) { return p >> 16; }
50
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
51

    
52

    
53
/*
54
 * Sets and their items are during parsing handled as lists, linked
55
 * through left ptr. The first item in a list also contains a pointer
56
 * to the last item in a list (right ptr). For convenience, even items
57
 * are handled as one-item lists. Lists are merged by f_merge_items().
58
 */
59
static int
60
f_valid_set_type(int type)
61
{
62
  switch (type)
63
  {
64
  case T_INT:
65
  case T_PAIR:
66
  case T_QUAD:
67
  case T_ENUM:
68
  case T_IP:
69
  case T_EC:
70
  case T_LC:
71
    return 1;
72

    
73
  default:
74
    return 0;
75
  }
76
}
77

    
78
static inline struct f_tree *
79
f_new_item(struct f_val from, struct f_val to)
80
{
81
  struct f_tree *t = f_new_tree();
82
  t->right = t;
83
  t->from = from;
84
  t->to = to;
85
  return t;
86
}
87

    
88
static inline struct f_tree *
89
f_merge_items(struct f_tree *a, struct f_tree *b)
90
{
91
  if (!a) return b;
92
  a->right->left = b;
93
  a->right = b->right;
94
  b->right = NULL;
95
  return a;
96
}
97

    
98
static inline struct f_tree *
99
f_new_pair_item(int fa, int ta, int fb, int tb)
100
{
101
  check_u16(fa);
102
  check_u16(ta);
103
  check_u16(fb);
104
  check_u16(tb);
105

    
106
  if ((ta < fa) || (tb < fb))
107
    cf_error( "From value cannot be higher that To value in pair sets");
108

    
109
  struct f_tree *t = f_new_tree();
110
  t->right = t;
111
  t->from.type = t->to.type = T_PAIR;
112
  t->from.val.i = pair(fa, fb);
113
  t->to.val.i = pair(ta, tb);
114
  return t;
115
}
116

    
117
static inline struct f_tree *
118
f_new_pair_set(int fa, int ta, int fb, int tb)
119
{
120
  check_u16(fa);
121
  check_u16(ta);
122
  check_u16(fb);
123
  check_u16(tb);
124

    
125
  if ((ta < fa) || (tb < fb))
126
    cf_error( "From value cannot be higher that To value in pair sets");
127

    
128
  struct f_tree *lst = NULL;
129
  int i;
130

    
131
  for (i = fa; i <= ta; i++)
132
    lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
133

    
134
  return lst;
135
}
136

    
137
#define CC_ALL 0xFFFF
138
#define EC_ALL 0xFFFFFFFF
139
#define LC_ALL 0xFFFFFFFF
140

    
141
static struct f_tree *
142
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
143
{
144
  u64 fm, to;
145

    
146
  if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
147
    check_u16(vf);
148
    if (vt == EC_ALL)
149
      vt = 0xFFFF;
150
    else
151
      check_u16(vt);
152
  }
153

    
154
  if (kind == EC_GENERIC) {
155
    fm = ec_generic(key, vf);
156
    to = ec_generic(key, vt);
157
  }
158
  else if (ipv4_used) {
159
    fm = ec_ip4(kind, key, vf);
160
    to = ec_ip4(kind, key, vt);
161
  }
162
  else if (key < 0x10000) {
163
    fm = ec_as2(kind, key, vf);
164
    to = ec_as2(kind, key, vt);
165
  }
166
  else {
167
    fm = ec_as4(kind, key, vf);
168
    to = ec_as4(kind, key, vt);
169
  }
170

    
171
  struct f_tree *t = f_new_tree();
172
  t->right = t;
173
  t->from.type = t->to.type = T_EC;
174
  t->from.val.ec = fm;
175
  t->to.val.ec = to;
176
  return t;
177
}
178

    
179
static struct f_tree *
180
f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
181
{
182
  struct f_tree *t = f_new_tree();
183
  t->right = t;
184
  t->from.type = t->to.type = T_LC;
185
  t->from.val.lc = (lcomm) {f1, f2, f3};
186
  t->to.val.lc = (lcomm) {t1, t2, t3};
187
  return t;
188
}
189

    
190
static inline struct f_inst *
191
f_generate_empty(struct f_inst *dyn)
192
{
193
  struct f_inst *e = f_new_inst();
194
  e->code = 'E';
195

    
196
  switch (dyn->aux & EAF_TYPE_MASK) {
197
    case EAF_TYPE_AS_PATH:
198
      e->aux = T_PATH;
199
      break;
200
    case EAF_TYPE_INT_SET:
201
      e->aux = T_CLIST;
202
      break;
203
    case EAF_TYPE_EC_SET:
204
      e->aux = T_ECLIST;
205
      break;
206
    case EAF_TYPE_LC_SET:
207
      e->aux = T_LCLIST;
208
      break;
209
    default:
210
      cf_error("Can't empty that attribute");
211
  }
212

    
213
  dyn->code = P('e','S');
214
  dyn->a1.p = e;
215
  return dyn;
216
}
217

    
218

    
219
static inline struct f_inst *
220
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
221
{
222
  struct f_inst *rv;
223

    
224
  if ((t1->code == 'c') && (t2->code == 'c')) {
225
    if ((t1->aux != T_INT) || (t2->aux != T_INT))
226
      cf_error( "Can't operate with value of non-integer type in pair constructor");
227

    
228
    check_u16(t1->a2.i);
229
    check_u16(t2->a2.i);
230

    
231
    rv = f_new_inst();
232
    rv->code = 'c';
233
    rv->aux = T_PAIR;
234
    rv->a2.i = pair(t1->a2.i, t2->a2.i);
235
  }
236
  else {
237
    rv = f_new_inst();
238
    rv->code = P('m', 'p');
239
    rv->a1.p = t1;
240
    rv->a2.p = t2;
241
  }
242

    
243
  return rv;
244
}
245

    
246
static inline struct f_inst *
247
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
248
{
249
  struct f_inst *rv;
250
  int c1 = 0, c2 = 0, ipv4_used = 0;
251
  u32 key = 0, val2 = 0;
252

    
253
  if (tk->code == 'c') {
254
    c1 = 1;
255

    
256
    if (tk->aux == T_INT) {
257
      ipv4_used = 0; key = tk->a2.i;
258
    }
259
    else if (tk->aux == T_QUAD) {
260
      ipv4_used = 1; key = tk->a2.i;
261
    }
262
    else
263
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
264
  }
265

    
266
  /* IP->Quad implicit conversion */
267
  else if (tk->code == 'C') {
268
    c1 = 1;
269
    struct f_val *val = tk->a1.p;
270

    
271
    if (val->type == T_INT) {
272
      ipv4_used = 0; key = val->val.i;
273
    }
274
    else if (val->type == T_QUAD) {
275
      ipv4_used = 1; key = val->val.i;
276
    }
277
    else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
278
      ipv4_used = 1; key = ipa_to_u32(val->val.ip);
279
    }
280
    else
281
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
282
  }
283

    
284
  if (tv->code == 'c') {
285
    if (tv->aux != T_INT)
286
      cf_error("Can't operate with value of non-integer type in EC constructor");
287
    c2 = 1;
288
    val2 = tv->a2.i;
289
  }
290

    
291
  if (c1 && c2) {
292
    u64 ec;
293

    
294
    if (kind == EC_GENERIC) {
295
      ec = ec_generic(key, val2);
296
    }
297
    else if (ipv4_used) {
298
      check_u16(val2);
299
      ec = ec_ip4(kind, key, val2);
300
    }
301
    else if (key < 0x10000) {
302
      ec = ec_as2(kind, key, val2);
303
    }
304
    else {
305
      check_u16(val2);
306
      ec = ec_as4(kind, key, val2);
307
    }
308

    
309
    NEW_F_VAL;
310
    rv = f_new_inst();
311
    rv->code = 'C';
312
    rv->a1.p = val;
313
    val->type = T_EC;
314
    val->val.ec = ec;
315
  }
316
  else {
317
    rv = f_new_inst();
318
    rv->code = P('m','c');
319
    rv->aux = kind;
320
    rv->a1.p = tk;
321
    rv->a2.p = tv;
322
  }
323

    
324
  return rv;
325
}
326

    
327
static inline struct f_inst *
328
f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
329
{
330
  struct f_inst *rv;
331

    
332
  if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) {
333
    if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
334
      cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
335

    
336
    rv = f_new_inst();
337
    rv->code = 'C';
338

    
339
    NEW_F_VAL;
340
    rv->a1.p = val;
341
    val->type = T_LC;
342
    val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
343
  }
344
  else
345
  {
346
    rv = cfg_allocz(sizeof(struct f_inst3));
347
    rv->lineno = ifs->lino;
348
    rv->code = P('m','l');
349
    rv->a1.p = t1;
350
    rv->a2.p = t2;
351
    INST3(rv).p = t3;
352
  }
353

    
354
  return rv;
355
}
356

    
357
/*
358
 * Remove all new lines and doubled whitespaces
359
 * and convert all tabulators to spaces
360
 * and return a copy of string
361
 */
362
char *
363
assert_copy_expr(const char *start, size_t len)
364
{
365
  /* XXX: Allocates maybe a little more memory than we really finally need */
366
  char *str = cfg_alloc(len + 1);
367

    
368
  char *dst = str;
369
  const char *src = start - 1;
370
  const char *end = start + len;
371
  while (++src < end)
372
  {
373
    if (*src == '\n')
374
      continue;
375

    
376
    /* Skip doubled whitespaces */
377
    if (src != start)
378
    {
379
      const char *prev = src - 1;
380
      if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
381
	continue;
382
    }
383

    
384
    if (*src == '\t')
385
      *dst = ' ';
386
    else
387
      *dst = *src;
388

    
389
    dst++;
390
  }
391
  *dst = '\0';
392

    
393
  return str;
394
}
395

    
396
/*
397
 * assert_done - create f_instruction of bt_assert
398
 * @expr: expression in bt_assert()
399
 * @start: pointer to first char of test expression
400
 * @end: pointer to the last char of test expression
401
 */
402
static struct f_inst *
403
assert_done(struct f_inst *expr, const char *start, const char *end)
404
{
405
  struct f_inst *i;
406
  i = f_new_inst();
407
  i->code = P('a','s');
408
  i->a1.p = expr;
409

    
410
  if (end >= start)
411
  {
412
    i->a2.p = assert_copy_expr(start, end - start + 1);
413
  }
414
  else
415
  {
416
    /* this is a break of lexer buffer */
417
    i->a2.p = "???";
418
  }
419

    
420
  return i;
421
}
422

    
423
/* Headers from nest/config.Y */
424

    
425
#include "nest/rt-dev.h"
426
#include "nest/password.h"
427
#include "nest/cmds.h"
428
#include "lib/lists.h"
429
#include "lib/mac.h"
430

    
431
/* Defines from nest/config.Y */
432

    
433
static struct proto_config *this_proto;
434
static struct channel_config *this_channel;
435
static struct iface_patt *this_ipatt;
436
static struct iface_patt_node *this_ipn;
437
/* static struct roa_table_config *this_roa_table; */
438
static list *this_p_list;
439
static struct password_item *this_p_item;
440
static int password_id;
441

    
442
static void
443
iface_patt_check(void)
444
{
445
  struct iface_patt_node *pn;
446

    
447
  WALK_LIST(pn, this_ipatt->ipn_list)
448
    if (!pn->pattern || pn->prefix.type)
449
      cf_error("Interface name/mask expected, not IP prefix");
450
}
451

    
452

    
453
static inline void
454
reset_passwords(void)
455
{
456
  this_p_list = NULL;
457
}
458

    
459
static inline list *
460
get_passwords(void)
461
{
462
  list *rv = this_p_list;
463
  this_p_list = NULL;
464
  return rv;
465
}
466

    
467
static void
468
proto_postconfig(void)
469
{
470
  CALL(this_proto->protocol->postconfig, this_proto);
471
  this_channel = NULL;
472
  this_proto = NULL;
473
}
474

    
475

    
476
#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
477

    
478
/* Headers from proto/bfd/config.Y */
479

    
480
#include "proto/bfd/bfd.h"
481

    
482
/* Defines from proto/bfd/config.Y */
483

    
484
#define BFD_CFG ((struct bfd_config *) this_proto)
485
#define BFD_IFACE ((struct bfd_iface_config *) this_ipatt)
486
#define BFD_NEIGHBOR this_bfd_neighbor
487

    
488
static struct bfd_neighbor *this_bfd_neighbor;
489

    
490
extern struct bfd_config *bfd_cf;
491

    
492
/* Headers from proto/babel/config.Y */
493

    
494
#include "proto/babel/babel.h"
495
#include "nest/iface.h"
496

    
497
/* Defines from proto/babel/config.Y */
498

    
499
#define BABEL_CFG ((struct babel_config *) this_proto)
500
#define BABEL_IFACE ((struct babel_iface_config *) this_ipatt)
501

    
502
/* Headers from proto/bgp/config.Y */
503

    
504
#include "proto/bgp/bgp.h"
505

    
506
/* Defines from proto/bgp/config.Y */
507

    
508
#define BGP_CFG ((struct bgp_config *) this_proto)
509
#define BGP_CC ((struct bgp_channel_config *) this_channel)
510

    
511
/* Headers from proto/ospf/config.Y */
512

    
513
#include "proto/ospf/ospf.h"
514

    
515
/* Defines from proto/ospf/config.Y */
516

    
517
#define OSPF_CFG ((struct ospf_config *) this_proto)
518
#define OSPF_PATT ((struct ospf_iface_patt *) this_ipatt)
519

    
520
static struct ospf_area_config *this_area;
521
static struct nbma_node *this_nbma;
522
static list *this_nets;
523
static struct area_net_config *this_pref;
524
static struct ospf_stubnet_config *this_stubnet;
525

    
526
static inline int ospf_cfg_is_v2(void) { return OSPF_CFG->ospf2; }
527
static inline int ospf_cfg_is_v3(void) { return ! OSPF_CFG->ospf2; }
528

    
529
static void
530
ospf_iface_finish(void)
531
{
532
  struct ospf_iface_patt *ip = OSPF_PATT;
533

    
534
  if (ip->deadint == 0)
535
    ip->deadint = ip->deadc * ip->helloint;
536

    
537
  if (ip->waitint == 0)
538
    ip->waitint = ip->deadc * ip->helloint;
539

    
540
  ip->passwords = get_passwords();
541

    
542
  if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
543
    log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks");
544

    
545
  if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
546
    log(L_WARN "Password option without authentication option does not make sense");
547

    
548
  if (ip->passwords)
549
  {
550
    struct password_item *pass;
551
    WALK_LIST(pass, *ip->passwords)
552
    {
553
      if (pass->alg && (ip->autype != OSPF_AUTH_CRYPT))
554
	cf_error("Password algorithm option requires cryptographic authentication");
555

    
556
      /* Set default OSPF crypto algorithms */
557
      if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT))
558
	pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256;
559
    }
560
  }
561
}
562

    
563
static void
564
ospf_area_finish(void)
565
{
566
  if ((this_area->areaid == 0) && (this_area->type != OPT_E))
567
    cf_error("Backbone area cannot be stub/NSSA");
568

    
569
  if (this_area->summary && (this_area->type == OPT_E))
570
    cf_error("Only stub/NSSA areas can use summary propagation");
571

    
572
  if (this_area->default_nssa && ((this_area->type != OPT_N) || ! this_area->summary))
573
    cf_error("Only NSSA areas with summary propagation can use NSSA default route");
574

    
575
  if ((this_area->default_cost & LSA_EXT3_EBIT) && ! this_area->default_nssa)
576
    cf_error("Only NSSA default route can use type 2 metric");
577
}
578

    
579
static void
580
ospf_proto_finish(void)
581
{
582
  struct ospf_config *cf = OSPF_CFG;
583
  struct ospf_area_config *ac;
584
  struct ospf_iface_patt *ic;
585

    
586
  /* Define default channel */
587
  if (EMPTY_LIST(this_proto->channels))
588
  {
589
    uint net_type = this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
590
    channel_config_new(NULL, net_label[net_type], net_type, this_proto);
591
  }
592

    
593
  /* Propagate global instance ID to interfaces */
594
  if (cf->instance_id_set)
595
  {
596
    WALK_LIST(ac, cf->area_list)
597
      WALK_LIST(ic, ac->patt_list)
598
	if (!ic->instance_id_set)
599
	{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
600

    
601
    WALK_LIST(ic, cf->vlink_list)
602
      if (!ic->instance_id_set)
603
      { ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
604
  }
605

    
606
  if (ospf_cfg_is_v3())
607
  {
608
    uint ipv4 = (this_proto->net_type == NET_IP4);
609
    uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
610

    
611
    /* RFC 5838 - OSPFv3-AF */
612
    if (cf->af_ext)
613
    {
614
      /* RFC 5838 2.1 - instance IDs based on AFs */
615
      WALK_LIST(ac, cf->area_list)
616
	WALK_LIST(ic, ac->patt_list)
617
	{
618
	  if (!ic->instance_id_set)
619
	    ic->instance_id = base;
620
	  else if (ic->instance_id >= 128)
621
	    log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
622
	  else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
623
	    cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
624
	}
625

    
626
      /* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
627
      if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
628
	cf_error("Vlinks not supported in AFs other than IPv6 unicast");
629
    }
630
    else
631
    {
632
      if (ipv4 || cf->af_mc)
633
	cf_error("Different channel type");
634
    }
635
  }
636

    
637
  if (EMPTY_LIST(cf->area_list))
638
    cf_error("No configured areas in OSPF");
639

    
640
  int areano = 0;
641
  int backbone = 0;
642
  int nssa = 0;
643
  WALK_LIST(ac, cf->area_list)
644
  {
645
    areano++;
646
    if (ac->areaid == 0)
647
      backbone = 1;
648
    if (ac->type == OPT_N)
649
      nssa = 1;
650
  }
651

    
652
  cf->abr = areano > 1;
653

    
654
  /* Route export or NSSA translation (RFC 3101 3.1) */
655
  cf->asbr = (proto_cf_main_channel(this_proto)->out_filter != FILTER_REJECT) || (nssa && cf->abr);
656

    
657
  if (cf->abr && !backbone)
658
  {
659
    struct ospf_area_config *ac = cfg_allocz(sizeof(struct ospf_area_config));
660
    ac->type = OPT_E; /* Backbone is non-stub */
661
    add_head(&cf->area_list, NODE ac);
662
    init_list(&ac->patt_list);
663
    init_list(&ac->net_list);
664
    init_list(&ac->enet_list);
665
    init_list(&ac->stubnet_list);
666
  }
667

    
668
  if (!cf->abr && !EMPTY_LIST(cf->vlink_list))
669
    cf_error("Vlinks cannot be used on single area router");
670

    
671
  if (cf->asbr && (areano == 1) && (this_area->type == 0))
672
    cf_error("ASBR must be in non-stub area");
673
}
674

    
675
static inline void
676
ospf_check_defcost(int cost)
677
{
678
  if ((cost <= 0) || (cost >= LSINFINITY))
679
   cf_error("Default cost must be in range 1-%u", LSINFINITY-1);
680
}
681

    
682
static inline void
683
ospf_check_auth(void)
684
{
685
  if (ospf_cfg_is_v3())
686
    cf_error("Authentication not supported in OSPFv3");
687
}
688

    
689

    
690
/* Headers from proto/pipe/config.Y */
691

    
692
#include "proto/pipe/pipe.h"
693

    
694
/* Defines from proto/pipe/config.Y */
695

    
696
#define PIPE_CFG ((struct pipe_config *) this_proto)
697

    
698
/* Headers from proto/radv/config.Y */
699

    
700
#include "proto/radv/radv.h"
701

    
702
/* Defines from proto/radv/config.Y */
703

    
704
#define RADV_CFG ((struct radv_config *) this_proto)
705
#define RADV_IFACE ((struct radv_iface_config *) this_ipatt)
706
#define RADV_PREFIX this_radv_prefix
707
#define RADV_RDNSS (&this_radv_rdnss)
708
#define RADV_DNSSL (&this_radv_dnssl)
709

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

    
716

    
717
/* Headers from proto/rip/config.Y */
718

    
719
#include "proto/rip/rip.h"
720
#include "nest/iface.h"
721

    
722
/* Defines from proto/rip/config.Y */
723

    
724
#define RIP_CFG ((struct rip_config *) this_proto)
725
#define RIP_IFACE ((struct rip_iface_config *) this_ipatt)
726

    
727
static inline int rip_cfg_is_v2(void) { return RIP_CFG->rip2; }
728
static inline int rip_cfg_is_ng(void) { return ! RIP_CFG->rip2; }
729

    
730
static inline void
731
rip_check_auth(void)
732
{
733
  if (rip_cfg_is_ng())
734
    cf_error("Authentication not supported in RIPng");
735
}
736

    
737

    
738
/* Headers from proto/static/config.Y */
739

    
740
#include "proto/static/static.h"
741

    
742
/* Defines from proto/static/config.Y */
743

    
744
#define STATIC_CFG ((struct static_config *) this_proto)
745
static struct static_route *this_srt, *this_snh;
746
static struct f_inst **this_srt_last_cmd;
747

    
748
static struct static_route *
749
static_nexthop_new(void)
750
{
751
  struct static_route *nh = this_srt;
752

    
753
  if (this_snh)
754
  {
755
    /* Additional next hop */
756
    nh = cfg_allocz(sizeof(struct static_route));
757
    nh->net = this_srt->net;
758
    this_snh->mp_next = nh;
759
  }
760

    
761
  nh->dest = RTD_UNICAST;
762
  nh->mp_head = this_srt;
763
  return nh;
764
};
765

    
766
static void
767
static_route_finish(void)
768
{
769
  if (net_type_match(this_srt->net, NB_DEST) == !this_srt->dest)
770
    cf_error("Unexpected or missing nexthop/type");
771
}
772

    
773
/* Headers from sysdep/linux/netlink.Y */
774

    
775
/* Headers from sysdep/unix/config.Y */
776

    
777
#include "sysdep/unix/unix.h"
778
#include <stdio.h>
779

    
780
/* Headers from sysdep/unix/krt.Y */
781

    
782
#include "sysdep/unix/krt.h"
783

    
784
/* Defines from sysdep/unix/krt.Y */
785

    
786
#define THIS_KRT ((struct krt_config *) this_proto)
787
#define THIS_KIF ((struct kif_config *) this_proto)
788
#define KIF_IFACE ((struct kif_iface_config *) this_ipatt)
789

    
790
static void
791
krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit)
792
{
793
  if ((limit <= 0) || (limit > 255))
794
    cf_error("Merge paths limit must be in range 1-255");
795

    
796
  cc->ra_mode = merge ? RA_MERGED : RA_OPTIMAL;
797
  cc->merge_limit = limit;
798
}
799

    
800
static void
801
kif_set_preferred(ip_addr ip)
802
{
803
  if (ipa_is_ip4(ip))
804
    KIF_IFACE->pref_v4 = ip;
805
  else if (!ipa_is_link_local(ip))
806
    KIF_IFACE->pref_v6 = ip;
807
  else
808
    KIF_IFACE->pref_ll = ip;
809
}
810

    
811
%}
812

    
813
/* Declarations from conf/confbase.Y */
814

    
815
%union {
816
  uint i;
817
  u32 i32;
818
  u64 i64;
819
  ip_addr a;
820
  ip4_addr ip4;
821
  ip6_addr ip6;
822
  net_addr net;
823
  net_addr *net_ptr;
824
  struct symbol *s;
825
  char *t;
826
  struct rtable_config *r;
827
  struct channel_config *cc;
828
  struct f_inst *x;
829
  struct filter *f;
830
  struct f_tree *e;
831
  struct f_trie *trie;
832
  struct f_val v;
833
  struct f_path_mask *h;
834
  struct password_item *p;
835
  struct rt_show_data *ra;
836
  struct sym_show_data *sd;
837
  struct lsadb_show_data *ld;
838
  struct iface *iface;
839
  void *g;
840
  btime time;
841
  struct f_prefix px;
842
  struct proto_spec ps;
843
  struct channel_limit cl;
844
  struct timeformat *tf;
845
  mpls_label_stack *mls;
846
}
847

    
848
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
849
%token GEQ LEQ NEQ AND OR
850
%token PO PC
851
%token <i> NUM ENUM
852
%token <ip4> IP4
853
%token <ip6> IP6
854
%token <i64> VPN_RD
855
%token <s> SYM
856
%token <t> TEXT
857
%type <iface> ipa_scope
858

    
859
%type <i> expr bool pxlen4
860
%type <time> expr_us time
861
%type <a> ipa
862
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
863
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mpls_
864
%type <mls> label_stack_start label_stack
865

    
866
%type <t> text opttext
867

    
868
%nonassoc PREFIX_DUMMY
869
%left AND OR
870
%nonassoc '=' '<' '>' '~' GEQ LEQ NEQ NMA PO PC
871
%left '+' '-'
872
%left '*' '/' '%'
873
%left '!'
874
%nonassoc '.'
875

    
876
%token DEFINE ON OFF YES NO S MS US PORT VPN MPLS
877

    
878
/* Declarations from conf/flowspec.Y */
879

    
880
%type <i32> flow_num_op flow_srcdst flow_logic_op flow_num_type_ flow_frag_val flow_neg
881
%type <net_ptr> net_flow4_ net_flow6_ net_flow_
882

    
883
%token FLOW4 FLOW6 DST SRC PROTO NEXT HEADER DPORT SPORT ICMP TYPE CODE TCP FLAGS LENGTH DSCP DONT_FRAGMENT IS_FRAGMENT FIRST_FRAGMENT LAST_FRAGMENT FRAGMENT LABEL OFFSET
884

    
885

    
886
/* Declarations from filter/config.Y */
887

    
888
%token FUNCTION PRINT PRINTN UNSET RETURN ACCEPT REJECT ERROR QUITBIRD INT BOOL IP PREFIX RD PAIR QUAD EC LC SET STRING BGPMASK BGPPATH CLIST ECLIST LCLIST IF THEN ELSE CASE TRUE FALSE RT RO UNKNOWN GENERIC FROM GW NET MASK SOURCE SCOPE DEST IFNAME IFINDEX PREFERENCE ROA_CHECK ASN IS_V4 IS_V6 LEN MAXLEN DEFINED ADD DELETE CONTAINS RESET PREPEND FIRST LAST LAST_NONAGGREGATED MATCH EMPTY FILTER WHERE EVAL BT_ASSERT BT_TEST_SUITE FORMAT
889

    
890
%nonassoc THEN
891
%nonassoc ELSE
892

    
893
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr
894
%type <f> filter filter_body where_filter
895
%type <i> type break_command ec_kind
896
%type <i32> cnum
897
%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
898
%type <trie> fprefix_set
899
%type <v> set_atom switch_atom fipa
900
%type <px> fprefix
901
%type <s> decls declsn one_decl function_params
902
%type <h> bgp_path bgp_path_tail
903
%type <t> get_cf_position
904

    
905
/* Declarations from nest/config.Y */
906

    
907
%token ROUTER ID PROTOCOL TEMPLATE DISABLED DEBUG ALL DIRECT
908
%token INTERFACE IMPORT EXPORT NONE VRF TABLE STATES ROUTES FILTERS
909
%token IPV4 IPV6 VPN4 VPN6 ROA4 ROA6
910
%token RECEIVE LIMIT ACTION WARN BLOCK RESTART DISABLE KEEP FILTERED
911
%token PASSWORD PASSIVE TO EVENTS PACKETS PROTOCOLS INTERFACES
912
%token ALGORITHM KEYED HMAC MD5 SHA1 SHA256 SHA384 SHA512
913
%token PRIMARY STATS COUNT BY FOR COMMANDS PREEXPORT NOEXPORT GENERATE
914
%token BGP PASSWORDS DESCRIPTION SORTED
915
%token RELOAD IN OUT MRTDUMP MESSAGES RESTRICT MEMORY IGP_METRIC CLASS
916
%token TIMEFORMAT ISO SHORT LONG ROUTE BASE LOG
917
%token GRACEFUL WAIT MAX FLUSH AS
918

    
919
/* For r_args_channel */
920
%token IPV4_MC IPV4_MPLS IPV6_MC IPV6_MPLS VPN4_MC VPN4_MPLS VPN6_MC VPN6_MPLS PRI SEC
921

    
922

    
923

    
924

    
925

    
926

    
927
%type <i32> idval
928
%type <f> imexport
929
%type <r> rtable
930
%type <s> optsym
931
%type <ra> r_args
932
%type <sd> sym_args
933
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode limit_action net_type table_sorted tos password_algorithm
934
%type <ps> proto_patt proto_patt2
935
%type <cc> channel_start proto_channel
936
%type <cl> limit_spec
937
%type <net> r_args_for_val
938
%type <net_ptr> r_args_for
939
%type <t> r_args_channel
940

    
941
%token SHOW STATUS
942
%token SUMMARY
943
%token SYMBOLS
944
%token DUMP RESOURCES
945
%token SOCKETS
946
%token NEIGHBORS
947
%token ATTRIBUTES
948
%token ECHO
949
%token ENABLE
950
/* Declarations from proto/bfd/config.Y */
951

    
952
%token BFD MIN IDLE RX TX INTERVAL MULTIPLIER MULTIHOP NEIGHBOR DEV LOCAL AUTHENTICATION SIMPLE METICULOUS
953

    
954
%type <iface> bfd_neigh_iface
955
%type <a> bfd_neigh_local
956
%type <i> bfd_neigh_multihop bfd_auth_type
957

    
958
%token SESSIONS
959
/* Declarations from proto/babel/config.Y */
960

    
961
%token BABEL METRIC RXCOST HELLO UPDATE WIRED WIRELESS BUFFER CHECK LINK BABEL_METRIC HOP
962

    
963
%token ENTRIES
964
/* Declarations from proto/bgp/config.Y */
965

    
966
%token HOLD TIME CONNECT RETRY KEEPALIVE STARTUP VIA SELF DEFAULT PATH START DELAY FORGET AFTER BGP_PATH BGP_LOCAL_PREF BGP_MED BGP_ORIGIN BGP_NEXT_HOP BGP_ATOMIC_AGGR BGP_AGGREGATOR BGP_COMMUNITY BGP_EXT_COMMUNITY BGP_LARGE_COMMUNITY ADDRESS RR RS CLIENT CLUSTER AS4 ADVERTISE CAPABILITIES PREFER OLDER MISSING LLADDR DROP IGNORE REFRESH INTERPRET COMMUNITIES BGP_ORIGINATOR_ID BGP_CLUSTER_LIST IGP GATEWAY RECURSIVE MED TTL SECURITY DETERMINISTIC SECONDARY ALLOW PATHS AWARE EXTENDED SETKEY STRICT BIND CONFEDERATION MEMBER MULTICAST
967

    
968
%type <i32> bgp_afi
969

    
970
/* Declarations from proto/ospf/config.Y */
971

    
972
%token OSPF V2 V3 OSPF_METRIC1 OSPF_METRIC2 OSPF_TAG OSPF_ROUTER_ID
973
%token AREA RFC1583COMPAT STUB TICK COST COST2 RETRANSMIT
974
%token TRANSMIT PRIORITY DEAD BROADCAST BCAST
975
%token NONBROADCAST NBMA POINTOPOINT PTP POINTOMULTIPOINT PTMP
976
%token CRYPTOGRAPHIC
977
%token ELIGIBLE POLL NETWORKS HIDDEN VIRTUAL ONLY
978
%token LARGE NORMAL STUBNET TAG EXTERNAL
979
%token LSADB ECMP WEIGHT NSSA TRANSLATOR STABILITY
980
%token GLOBAL LSID INSTANCE REAL NETMASK
981
%token MERGE LSA SUPPRESSION RFC5838
982

    
983
%type <ld> lsadb_args
984
%type <i> ospf_variant ospf_af_mc nbma_eligible
985
%type <cc> ospf_channel_start ospf_channel
986

    
987
%token TOPOLOGY
988
%token STATE
989
/* Declarations from proto/pipe/config.Y */
990

    
991
%token PIPE PEER
992

    
993
/* Declarations from proto/radv/config.Y */
994

    
995
%token RADV RA MANAGED OTHER CONFIG LINGER MTU REACHABLE RETRANS TIMER CURRENT VALID PREFERRED MULT LIFETIME SKIP ONLINK AUTONOMOUS RDNSS DNSSL NS DOMAIN TRIGGER SENSITIVE LOW MEDIUM HIGH PROPAGATE RA_PREFERENCE RA_LIFETIME
996

    
997

    
998

    
999
%type<i> radv_mult radv_sensitive radv_preference
1000

    
1001
/* Declarations from proto/rip/config.Y */
1002

    
1003
%token RIP NG INFINITY TIMEOUT GARBAGE MODE VERSION SPLIT HORIZON POISON REVERSE ZERO PLAINTEXT RIP_METRIC RIP_TAG
1004

    
1005
%type <i> rip_variant rip_auth
1006

    
1007
/* Declarations from proto/static/config.Y */
1008

    
1009
%token STATIC PROHIBIT
1010
%token BLACKHOLE UNREACHABLE
1011

    
1012

    
1013
/* Declarations from sysdep/linux/netlink.Y */
1014

    
1015
%token KERNEL KRT_PREFSRC KRT_REALM KRT_SCOPE KRT_MTU KRT_WINDOW KRT_RTT KRT_RTTVAR KRT_SSTRESH KRT_CWND KRT_ADVMSS KRT_REORDERING KRT_HOPLIMIT KRT_INITCWND KRT_RTO_MIN KRT_INITRWND KRT_QUICKACK KRT_LOCK_MTU KRT_LOCK_WINDOW KRT_LOCK_RTT KRT_LOCK_RTTVAR KRT_LOCK_SSTRESH KRT_LOCK_CWND KRT_LOCK_ADVMSS KRT_LOCK_REORDERING KRT_LOCK_HOPLIMIT KRT_LOCK_RTO_MIN KRT_FEATURE_ECN KRT_FEATURE_ALLFRAG
1016

    
1017
/* Declarations from sysdep/unix/config.Y */
1018

    
1019
%token SYSLOG TRACE INFO REMOTE WARNING AUTH FATAL BUG STDERR SOFT
1020
%token NAME CONFIRM UNDO LATENCY WATCHDOG
1021

    
1022
%type <i> log_mask log_mask_list log_cat cfg_timeout
1023
%type <g> log_file
1024
%type <t> cfg_name
1025
%type <tf> timeformat_which
1026
%type <t> syslog_name
1027

    
1028
%token CONFIGURE
1029
%token DOWN
1030
/* Declarations from sysdep/unix/krt.Y */
1031

    
1032
%token PERSIST SCAN LEARN DEVICE KRT_SOURCE KRT_METRIC
1033

    
1034
%type <i> kern_mp_limit
1035

    
1036

    
1037
%%
1038
/* Grammar from conf/confbase.Y */
1039

    
1040
/* Basic config file structure */
1041

    
1042
config: conf_entries END { return 0; }
1043
 | CLI_MARKER cli_cmd { return 0; }
1044
 ;
1045

    
1046
conf_entries:
1047
   /* EMPTY */
1048
 | conf_entries conf
1049
 ;
1050

    
1051

    
1052

    
1053
/* Constant expressions */
1054

    
1055
definition:
1056
   DEFINE SYM '=' term ';' {
1057
     struct f_val *val = cfg_alloc(sizeof(struct f_val));
1058
     *val = f_eval($4, cfg_mem);
1059
     if (val->type == T_RETURN) cf_error("Runtime error");
1060
     cf_define_symbol($2, SYM_CONSTANT | val->type, val);
1061
   }
1062
 ;
1063

    
1064
expr:
1065
   NUM
1066
 | '(' term ')' { $$ = f_eval_int($2); }
1067
 | SYM {
1068
     if ($1->class != (SYM_CONSTANT | T_INT)) cf_error("Number expected");
1069
     $$ = SYM_VAL($1).i; }
1070
 ;
1071

    
1072

    
1073
expr_us:
1074
   expr S  { $$ = $1 S_; }
1075
 | expr MS { $$ = $1 MS_; }
1076
 | expr US { $$ = $1 US_; }
1077
 ;
1078

    
1079
/* Switches */
1080

    
1081
bool:
1082
   expr { $$ = !!$1; }
1083
 | ON { $$ = 1; }
1084
 | YES { $$ = 1; }
1085
 | OFF { $$ = 0; }
1086
 | NO { $$ = 0; }
1087
 | /* Silence means agreement */ { $$ = 1; }
1088
 ;
1089

    
1090

    
1091
/* Addresses */
1092

    
1093
ipa:
1094
   IP4 { $$ = ipa_from_ip4($1); }
1095
 | IP6 { $$ = ipa_from_ip6($1); }
1096
 | SYM {
1097
     if ($1->class != (SYM_CONSTANT | T_IP)) cf_error("IP address expected");
1098
     $$ = SYM_VAL($1).ip;
1099
   }
1100
 ;
1101

    
1102
ipa_scope:
1103
   /* empty */ { $$ = NULL; }
1104
 | '%' SYM { $$ = if_get_by_name($2->name); }
1105
 ;
1106

    
1107

    
1108
/* Networks - internal */
1109

    
1110
pxlen4:
1111
   '/' NUM {
1112
     if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
1113
     $$ = $2;
1114
   }
1115
 | ':' IP4 {
1116
     $$ = ip4_masklen($2);
1117
     if ($$ == 255) cf_error("Invalid netmask %I4", $2);
1118
   }
1119
 ;
1120

    
1121
net_ip4_: IP4 pxlen4
1122
{
1123
  net_fill_ip4(&($$), $1, $2);
1124

    
1125
  net_addr_ip4 *n = (void *) &($$);
1126
  if (!net_validate_ip4(n))
1127
    cf_error("Invalid IPv4 prefix %I4/%d, maybe you wanted %I4/%d",
1128
	     n->prefix, n->pxlen, ip4_and(n->prefix, ip4_mkmask(n->pxlen)), n->pxlen);
1129
};
1130

    
1131
net_ip6_: IP6 '/' NUM
1132
{
1133
  if ($3 > IP6_MAX_PREFIX_LENGTH)
1134
    cf_error("Invalid prefix length %u", $3);
1135

    
1136
  net_fill_ip6(&($$), $1, $3);
1137

    
1138
  net_addr_ip6 *n = (void *) &($$);
1139
  if (!net_validate_ip6(n))
1140
    cf_error("Invalid IPv6 prefix %I6/%d, maybe you wanted %I6/%d",
1141
	     n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
1142
};
1143

    
1144
net_vpn4_: VPN_RD net_ip4_
1145
{
1146
  $$ = cfg_alloc(sizeof(net_addr_vpn4));
1147
  net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
1148
}
1149

    
1150
net_vpn6_: VPN_RD net_ip6_
1151
{
1152
  $$ = cfg_alloc(sizeof(net_addr_vpn6));
1153
  net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
1154
}
1155

    
1156
net_roa4_: net_ip4_ MAX NUM AS NUM
1157
{
1158
  $$ = cfg_alloc(sizeof(net_addr_roa4));
1159
  net_fill_roa4($$, net4_prefix(&$1), net4_pxlen(&$1), $3, $5);
1160
  if ($3 < net4_pxlen(&$1) || $3 > IP4_MAX_PREFIX_LENGTH)
1161
    cf_error("Invalid max prefix length %u", $3);
1162
};
1163

    
1164
net_roa6_: net_ip6_ MAX NUM AS NUM
1165
{
1166
  $$ = cfg_alloc(sizeof(net_addr_roa6));
1167
  net_fill_roa6($$, net6_prefix(&$1), net6_pxlen(&$1), $3, $5);
1168
  if ($3 < net6_pxlen(&$1) || $3 > IP6_MAX_PREFIX_LENGTH)
1169
    cf_error("Invalid max prefix length %u", $3);
1170
};
1171

    
1172
net_mpls_: MPLS NUM
1173
{
1174
  $$ = cfg_alloc(sizeof(net_addr_roa6));
1175
  net_fill_mpls($$, $2);
1176
}
1177

    
1178
net_ip_: net_ip4_ | net_ip6_ ;
1179
net_vpn_: net_vpn4_ | net_vpn6_ ;
1180
net_roa_: net_roa4_ | net_roa6_ ;
1181

    
1182
net_:
1183
   net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
1184
 | net_vpn_
1185
 | net_roa_
1186
 | net_flow_
1187
 | net_mpls_
1188
 ;
1189

    
1190

    
1191
/* Networks - regular */
1192

    
1193
net_ip6:
1194
   net_ip6_
1195
 | SYM {
1196
     if (($1->class != (SYM_CONSTANT | T_NET)) || (SYM_VAL($1).net->type != NET_IP6))
1197
       cf_error("IPv6 network expected");
1198
     $$ = * SYM_VAL($1).net;
1199
   }
1200
 ;
1201

    
1202
net_ip:
1203
   net_ip_
1204
 | SYM {
1205
     if (($1->class != (SYM_CONSTANT | T_NET)) || !net_is_ip(SYM_VAL($1).net))
1206
       cf_error("IP network expected");
1207
     $$ = * SYM_VAL($1).net;
1208
   }
1209
 ;
1210

    
1211
net_any:
1212
   net_
1213
 | SYM {
1214
     if ($1->class != (SYM_CONSTANT | T_NET))
1215
       cf_error("Network expected");
1216
     $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
1217
   }
1218
 ;
1219

    
1220
net_or_ipa:
1221
   net_ip4_
1222
 | net_ip6_
1223
 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
1224
 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
1225
 | SYM {
1226
     if ($1->class == (SYM_CONSTANT | T_IP))
1227
       net_fill_ip_host(&($$), SYM_VAL($1).ip);
1228
     else if (($1->class == (SYM_CONSTANT | T_NET)) && net_is_ip(SYM_VAL($1).net))
1229
       $$ = * SYM_VAL($1).net;
1230
     else
1231
       cf_error("IP address or network expected");
1232
   }
1233
 ;
1234

    
1235
label_stack_start: NUM
1236
{
1237
  $$ = cfg_allocz(sizeof(mpls_label_stack));
1238
  $$->len = 1;
1239
  $$->stack[0] = $1;
1240
};
1241

    
1242
label_stack:
1243
    label_stack_start
1244
  | label_stack '/' NUM {
1245
    if ($1->len >= MPLS_MAX_LABEL_STACK)
1246
      cf_error("Too many labels in stack");
1247
    $1->stack[$1->len++] = $3;
1248
    $$ = $1;
1249
  }
1250
;
1251

    
1252
time:
1253
   TEXT {
1254
     $$ = tm_parse_time($1);
1255
     if (!$$)
1256
       cf_error("Invalid date/time");
1257
   }
1258
 ;
1259

    
1260
text:
1261
   TEXT
1262
 | SYM {
1263
     if ($1->class != (SYM_CONSTANT | T_STRING)) cf_error("String expected");
1264
     $$ = SYM_VAL($1).s;
1265
   }
1266
 ;
1267

    
1268
opttext:
1269
    TEXT
1270
 | /* empty */ { $$ = NULL; }
1271
 ;
1272

    
1273

    
1274
/* Grammar from conf/flowspec.Y */
1275

    
1276
/* Network Flow Specification */
1277

    
1278
flow_num_op:
1279
   TRUE		{ $$ = FLOW_OP_TRUE; }
1280
 | '='		{ $$ = FLOW_OP_EQ;  }
1281
 | NEQ		{ $$ = FLOW_OP_NEQ; }
1282
 | '<'		{ $$ = FLOW_OP_LT;  }
1283
 | LEQ		{ $$ = FLOW_OP_LEQ; }
1284
 | '>'		{ $$ = FLOW_OP_GT;  }
1285
 | GEQ		{ $$ = FLOW_OP_GEQ; }
1286
 | FALSE	{ $$ = FLOW_OP_FALSE; }
1287
 ;
1288

    
1289
flow_logic_op:
1290
   OR		{ $$ = FLOW_OP_OR; }
1291
 | AND		{ $$ = FLOW_OP_AND; }
1292
 ;
1293

    
1294
flow_num_type_:
1295
   PROTO	{ $$ = FLOW_TYPE_IP_PROTOCOL; }
1296
 | NEXT HEADER  { $$ = FLOW_TYPE_NEXT_HEADER; }
1297
 | PORT		{ $$ = FLOW_TYPE_PORT; }
1298
 | DPORT	{ $$ = FLOW_TYPE_DST_PORT; }
1299
 | SPORT	{ $$ = FLOW_TYPE_SRC_PORT; }
1300
 | ICMP TYPE	{ $$ = FLOW_TYPE_ICMP_TYPE; }
1301
 | ICMP CODE	{ $$ = FLOW_TYPE_ICMP_CODE; }
1302
 | LENGTH	{ $$ = FLOW_TYPE_PACKET_LENGTH; }
1303
 | DSCP		{ $$ = FLOW_TYPE_DSCP; }
1304
 ;
1305

    
1306
flow_num_type: flow_num_type_{ flow_builder_set_type(this_flow, $1); };
1307
flow_flag_type: TCP FLAGS    { flow_builder_set_type(this_flow, FLOW_TYPE_TCP_FLAGS); };
1308
flow_frag_type: FRAGMENT     { flow_builder_set_type(this_flow, FLOW_TYPE_FRAGMENT); };
1309
flow_label_type: LABEL       { flow_builder_set_type(this_flow, FLOW_TYPE_LABEL); };
1310

    
1311
flow_srcdst:
1312
   DST		{ $$ = FLOW_TYPE_DST_PREFIX; }
1313
 | SRC		{ $$ = FLOW_TYPE_SRC_PREFIX; }
1314
 ;
1315

    
1316
flow_num_opts:
1317
   flow_num_op expr {
1318
     flow_check_cf_value_length(this_flow, $2);
1319
     flow_builder_add_op_val(this_flow, $1, $2);
1320
   }
1321
 | flow_num_opts flow_logic_op flow_num_op expr {
1322
     flow_check_cf_value_length(this_flow, $4);
1323
     flow_builder_add_op_val(this_flow, $2 | $3, $4);
1324
   }
1325
 | flow_num_opt_ext
1326
 | flow_num_opts OR flow_num_opt_ext
1327
 ;
1328

    
1329
flow_num_opt_ext_expr:
1330
   expr {
1331
     flow_check_cf_value_length(this_flow, $1);
1332
     flow_builder_add_op_val(this_flow, FLOW_OP_EQ, $1);
1333
   }
1334
 | expr DDOT expr {
1335
     flow_check_cf_value_length(this_flow, $1);
1336
     flow_check_cf_value_length(this_flow, $3);
1337
     flow_builder_add_op_val(this_flow, FLOW_OP_GEQ, $1);
1338
     flow_builder_add_op_val(this_flow, FLOW_OP_AND | FLOW_OP_LEQ, $3);
1339
   }
1340
 ;
1341

    
1342
flow_num_opt_ext:
1343
   flow_num_opt_ext_expr
1344
 | flow_num_opt_ext ',' flow_num_opt_ext_expr
1345
 ;
1346

    
1347
flow_bmk_opts:
1348
   flow_neg expr '/' expr {
1349
     flow_check_cf_bmk_values(this_flow, $1, $2, $4);
1350
     flow_builder_add_val_mask(this_flow, $1, $2, $4);
1351
   }
1352
 | flow_bmk_opts flow_logic_op flow_neg expr '/' expr {
1353
     flow_check_cf_bmk_values(this_flow, $3, $4, $6);
1354
     flow_builder_add_val_mask(this_flow, $2 | $3, $4, $6);
1355
   }
1356
 | flow_bmk_opts ',' flow_neg expr '/' expr {
1357
     flow_check_cf_bmk_values(this_flow, $3, $4, $6);
1358
     flow_builder_add_val_mask(this_flow, 0x40 | $3, $4, $6); /* AND */
1359
   }
1360
 ;
1361

    
1362
flow_neg:
1363
   /* empty */ 	{ $$ = 0x00; }
1364
 | '!'		{ $$ = 0x02; }
1365
 ;
1366

    
1367
flow_frag_val:
1368
   DONT_FRAGMENT  { $$ = 1; }
1369
 | IS_FRAGMENT	  { $$ = 2; }
1370
 | FIRST_FRAGMENT { $$ = 4; }
1371
 | LAST_FRAGMENT  { $$ = 8; }
1372
 ;
1373

    
1374
flow_frag_opts:
1375
   flow_neg flow_frag_val {
1376
     flow_builder_add_val_mask(this_flow, 0, ($1 ? 0 : $2), $2);
1377
   }
1378
 | flow_frag_opts flow_logic_op flow_neg flow_frag_val {
1379
     flow_builder_add_val_mask(this_flow, $2, ($3 ? 0 : $4), $4);
1380
   }
1381
 | flow_frag_opts ',' flow_neg flow_frag_val {
1382
     flow_builder_add_val_mask(this_flow, 0x40, ($3 ? 0 : $4), $4); /* AND */
1383
   }
1384
 ;
1385

    
1386
flow4_item:
1387
   flow_srcdst net_ip {
1388
     flow_builder_set_type(this_flow, $1);
1389
     flow_builder4_add_pfx(this_flow, (net_addr_ip4 *) &($2));
1390
   }
1391
 | flow_num_type flow_num_opts
1392
 | flow_flag_type flow_bmk_opts
1393
 | flow_frag_type flow_frag_opts
1394
 ;
1395

    
1396
flow6_item:
1397
   flow_srcdst net_ip6 {
1398
     flow_builder_set_type(this_flow, $1);
1399
     flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), 0);
1400
   }
1401
 | flow_srcdst net_ip6 OFFSET NUM {
1402
     if ($4 > $2.pxlen)
1403
       cf_error("Prefix offset is higher than prefix length");
1404
     flow_builder_set_type(this_flow, $1);
1405
     flow_builder6_add_pfx(this_flow, (net_addr_ip6 *) &($2), $4);
1406
   }
1407
 | flow_num_type flow_num_opts
1408
 | flow_flag_type flow_bmk_opts
1409
 | flow_frag_type flow_frag_opts
1410
 | flow_label_type flow_bmk_opts
1411
 ;
1412

    
1413
flow4_opts:
1414
   /* empty */
1415
 | flow4_opts flow4_item ';'
1416
 ;
1417

    
1418
flow6_opts:
1419
 /* empty */
1420
 | flow6_opts flow6_item ';'
1421
 ;
1422

    
1423
flow_builder_init:
1424
{
1425
  if (this_flow == NULL)
1426
    this_flow = flow_builder_init(&root_pool);
1427
  else
1428
    flow_builder_clear(this_flow);
1429
};
1430

    
1431
flow_builder_set_ipv4: { this_flow->ipv6 = 0; };
1432
flow_builder_set_ipv6: { this_flow->ipv6 = 1; };
1433

    
1434
net_flow4_: FLOW4 '{' flow_builder_init flow_builder_set_ipv4 flow4_opts '}'
1435
{
1436
  $$ = (net_addr *) flow_builder4_finalize(this_flow, cfg_mem);
1437
  flow4_validate_cf((net_addr_flow4 *) $$);
1438
};
1439

    
1440
net_flow6_: FLOW6 '{' flow_builder_init flow_builder_set_ipv6 flow6_opts '}'
1441
{
1442
  $$ = (net_addr *) flow_builder6_finalize(this_flow, cfg_mem);
1443
  flow6_validate_cf((net_addr_flow6 *) $$);
1444
};
1445

    
1446
net_flow_: net_flow4_ | net_flow6_ ;
1447

    
1448

    
1449
/* Grammar from filter/config.Y */
1450

    
1451
filter_def:
1452
   FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
1453
     filter_body {
1454
     $2->def = $4;
1455
     $4->name = $2->name;
1456
     DBG( "We have new filter defined (%s)\n", $2->name );
1457
     cf_pop_scope();
1458
   }
1459
 ;
1460

    
1461
filter_eval:
1462
   EVAL term { f_eval_int($2); }
1463
 ;
1464

    
1465
bt_test_suite:
1466
 BT_TEST_SUITE '(' SYM ',' text ')' {
1467
  if (!($3->class & SYM_FUNCTION))
1468
    cf_error("Function expected");
1469

    
1470
  struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
1471
  t->fn = $3->def;
1472
  t->fn_name = $3->name;
1473
  t->dsc = $5;
1474

    
1475
  add_tail(&new_config->tests, &t->n);
1476
 }
1477
 ;
1478

    
1479
type:
1480
   INT { $$ = T_INT; }
1481
 | BOOL { $$ = T_BOOL; }
1482
 | IP { $$ = T_IP; }
1483
 | RD { $$ = T_RD; }
1484
 | PREFIX { $$ = T_NET; }
1485
 | PAIR { $$ = T_PAIR; }
1486
 | QUAD { $$ = T_QUAD; }
1487
 | EC { $$ = T_EC; }
1488
 | LC { $$ = T_LC; }
1489
 | STRING { $$ = T_STRING; }
1490
 | BGPMASK { $$ = T_PATH_MASK; }
1491
 | BGPPATH { $$ = T_PATH; }
1492
 | CLIST { $$ = T_CLIST; }
1493
 | ECLIST { $$ = T_ECLIST; }
1494
 | LCLIST { $$ = T_LCLIST; }
1495
 | type SET {
1496
	switch ($1) {
1497
	  case T_INT:
1498
	  case T_PAIR:
1499
	  case T_QUAD:
1500
	  case T_EC:
1501
	  case T_LC:
1502
	  case T_IP:
1503
	       $$ = T_SET;
1504
	       break;
1505

    
1506
	  case T_NET:
1507
	       $$ = T_PREFIX_SET;
1508
	    break;
1509

    
1510
	  default:
1511
		cf_error( "You can't create sets of this type." );
1512
	}
1513
   }
1514
 ;
1515

    
1516
one_decl:
1517
   type SYM {
1518
     struct f_val * val = cfg_alloc(sizeof(struct f_val));
1519
     val->type = T_VOID;
1520
     $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
1521
     DBG( "New variable %s type %x\n", $2->name, $1 );
1522
     $2->aux2 = NULL;
1523
     $$=$2;
1524
   }
1525
 ;
1526

    
1527
/* Decls with ';' at the end */
1528
decls: /* EMPTY */ { $$ = NULL; }
1529
 | one_decl ';' decls {
1530
     $$ = $1;
1531
     $$->aux2 = $3;
1532
   }
1533
 ;
1534

    
1535
/* Declarations that have no ';' at the end. */
1536
declsn: one_decl { $$ = $1; }
1537
 | one_decl ';' declsn {
1538
     $$ = $1;
1539
     $$->aux2 = $3;
1540
   }
1541
 ;
1542

    
1543
filter_body:
1544
   function_body {
1545
     struct filter *f = cfg_alloc(sizeof(struct filter));
1546
     f->name = NULL;
1547
     f->root = $1;
1548
     $$ = f;
1549
   }
1550
 ;
1551

    
1552
filter:
1553
   SYM {
1554
     if ($1->class != SYM_FILTER) cf_error("No such filter.");
1555
     $$ = $1->def;
1556
   }
1557
 | filter_body
1558
 ;
1559

    
1560
where_filter:
1561
   WHERE term {
1562
     /* Construct 'IF term THEN ACCEPT; REJECT;' */
1563
     struct filter *f = cfg_alloc(sizeof(struct filter));
1564
     struct f_inst *i, *acc, *rej;
1565
     acc = f_new_inst();		/* ACCEPT */
1566
     acc->code = P('p',',');
1567
     acc->a1.p = NULL;
1568
     acc->a2.i = F_ACCEPT;
1569
     rej = f_new_inst();		/* REJECT */
1570
     rej->code = P('p',',');
1571
     rej->a1.p = NULL;
1572
     rej->a2.i = F_REJECT;
1573
     i = f_new_inst();			/* IF */
1574
     i->code = '?';
1575
     i->a1.p = $2;
1576
     i->a2.p = acc;
1577
     i->next = rej;
1578
     f->name = NULL;
1579
     f->root = i;
1580
     $$ = f;
1581
  }
1582
 ;
1583

    
1584
function_params:
1585
   '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
1586
 | '(' ')' { $$=NULL; }
1587
 ;
1588

    
1589
function_body:
1590
   decls '{' cmds '}' {
1591
     if ($1) {
1592
       /* Prepend instruction to clear local variables */
1593
       $$ = f_new_inst();
1594
       $$->code = P('c','v');
1595
       $$->a1.p = $1;
1596
       $$->next = $3;
1597
     } else
1598
       $$ = $3;
1599
   }
1600
 ;
1601

    
1602
function_def:
1603
   FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
1604
     $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
1605
     cf_push_scope($2);
1606
   } function_params function_body {
1607
     $2->def = $5;
1608
     $2->aux2 = $4;
1609
     DBG("Hmm, we've got one function here - %s\n", $2->name);
1610
     cf_pop_scope();
1611
   }
1612
 ;
1613

    
1614
/* Programs */
1615

    
1616
/* Hack: $$ of cmds_int is the last node.
1617
   $$->next of cmds_int is temporary used for the first node */
1618

    
1619
cmds: /* EMPTY */ { $$ = NULL; }
1620
 | cmds_int { $$ = $1->next; $1->next = NULL; }
1621
 ;
1622

    
1623
cmds_int: cmd { $$ = $1; $1->next = $1; }
1624
 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
1625
 ;
1626

    
1627
block:
1628
   cmd {
1629
     $$=$1;
1630
   }
1631
 | '{' cmds '}' {
1632
     $$=$2;
1633
   }
1634
 ;
1635

    
1636
/*
1637
 * Complex types, their bison value is struct f_val
1638
 */
1639
fipa:
1640
   IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
1641
 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
1642
 ;
1643

    
1644

    
1645

    
1646
/*
1647
 * Set constants. They are also used in switch cases. We use separate
1648
 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
1649
 * to elude a collision between symbol (in expr) in set_atom and symbol
1650
 * as a function call in switch case cmds.
1651
 */
1652

    
1653
set_atom:
1654
   NUM   { $$.type = T_INT; $$.val.i = $1; }
1655
 | fipa  { $$ = $1; }
1656
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
1657
 | '(' term ')' {
1658
     $$ = f_eval($2, cfg_mem);
1659
     if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
1660
   }
1661
 | SYM {
1662
     if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
1663
     if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
1664
     $$ = *(struct f_val *)($1->def);
1665
   }
1666
 ;
1667

    
1668
switch_atom:
1669
   NUM   { $$.type = T_INT; $$.val.i = $1; }
1670
 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
1671
 | fipa  { $$ = $1; }
1672
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
1673
 ;
1674

    
1675
cnum:
1676
   term { $$ = f_eval_int($1); }
1677

    
1678
pair_item:
1679
   '(' cnum ',' cnum ')'		{ $$ = f_new_pair_item($2, $2, $4, $4); }
1680
 | '(' cnum ',' cnum DDOT cnum ')'	{ $$ = f_new_pair_item($2, $2, $4, $6); }
1681
 | '(' cnum ',' '*' ')'			{ $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
1682
 | '(' cnum DDOT cnum ',' cnum ')'	{ $$ = f_new_pair_set($2, $4, $6, $6); }
1683
 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
1684
 | '(' cnum DDOT cnum ',' '*' ')'	{ $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
1685
 | '(' '*' ',' cnum ')'			{ $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
1686
 | '(' '*' ',' cnum DDOT cnum ')'	{ $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
1687
 | '(' '*' ',' '*' ')'			{ $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
1688
 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
1689
   { $$ = f_new_pair_item($2, $8, $4, $10); }
1690
 ;
1691

    
1692
ec_kind:
1693
   RT { $$ = EC_RT; }
1694
 | RO { $$ = EC_RO; }
1695
 | UNKNOWN NUM { $$ = $2; }
1696
 | GENERIC { $$ = EC_GENERIC; }
1697
 ;
1698

    
1699
ec_item:
1700
   '(' ec_kind ',' cnum ',' cnum ')'		{ $$ = f_new_ec_item($2, 0, $4, $6, $6); }
1701
 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')'	{ $$ = f_new_ec_item($2, 0, $4, $6, $8); }
1702
 | '(' ec_kind ',' cnum ',' '*' ')'		{ $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
1703
 ;
1704

    
1705
lc_item:
1706
   '(' cnum ',' cnum ',' cnum ')'	    { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
1707
 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
1708
 | '(' cnum ',' cnum ',' '*' ')'	    { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
1709
 | '(' cnum ',' cnum DDOT cnum ',' '*' ')'  { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
1710
 | '(' cnum ',' '*' ',' '*' ')'		    { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
1711
 | '(' cnum DDOT cnum ',' '*' ',' '*' ')'   { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
1712
 | '(' '*' ',' '*' ',' '*' ')'		    { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
1713
 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
1714
   { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
1715
;
1716

    
1717
set_item:
1718
   pair_item
1719
 | ec_item
1720
 | lc_item
1721
 | set_atom { $$ = f_new_item($1, $1); }
1722
 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
1723
 ;
1724

    
1725
switch_item:
1726
   pair_item
1727
 | ec_item
1728
 | lc_item
1729
 | switch_atom { $$ = f_new_item($1, $1); }
1730
 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
1731
 ;
1732

    
1733
set_items:
1734
   set_item
1735
 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
1736
 ;
1737

    
1738
switch_items:
1739
   switch_item
1740
 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
1741
 ;
1742

    
1743
fprefix:
1744
   net_ip_	{ $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
1745
 | net_ip_ '+'	{ $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
1746
 | net_ip_ '-'	{ $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
1747
 | net_ip_ '{' NUM ',' NUM '}' {
1748
     $$.net = $1; $$.lo = $3; $$.hi = $5;
1749
     if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
1750
       cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
1751
   }
1752
 ;
1753

    
1754
fprefix_set:
1755
   fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
1756
 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
1757
 ;
1758

    
1759
switch_body: /* EMPTY */ { $$ = NULL; }
1760
 | switch_body switch_items ':' cmds  {
1761
     /* Fill data fields */
1762
     struct f_tree *t;
1763
     for (t = $2; t; t = t->left)
1764
       t->data = $4;
1765
     $$ = f_merge_items($1, $2);
1766
   }
1767
 | switch_body ELSECOL cmds {
1768
     struct f_tree *t = f_new_tree();
1769
     t->from.type = t->to.type = T_VOID;
1770
     t->right = t;
1771
     t->data = $3;
1772
     $$ = f_merge_items($1, t);
1773
 }
1774
 ;
1775

    
1776
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
1777

    
1778
bgp_path_expr:
1779
   symbol       { $$ = $1; }
1780
 | '(' term ')' { $$ = $2; }
1781
 ;
1782

    
1783
bgp_path:
1784
   PO  bgp_path_tail PC  { $$ = $2; }
1785
 ;
1786

    
1787
bgp_path_tail:
1788
   NUM bgp_path_tail		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
1789
 | NUM DDOT NUM bgp_path_tail	{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
1790
 | '*' bgp_path_tail		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
1791
 | '?' bgp_path_tail		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
1792
 | bgp_path_expr bgp_path_tail	{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
1793
 | 				{ $$ = NULL; }
1794
 ;
1795

    
1796
constant:
1797
   NUM    { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT;  $$->a2.i = $1; }
1798
 | TRUE   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1;  }
1799
 | FALSE  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0;  }
1800
 | TEXT   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
1801
 | fipa	  { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
1802
 | VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
1803
 | net_   { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
1804
 | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
1805
 | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET;  $$->a2.p = $2; }
1806
 | ENUM	  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
1807
 | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
1808
 ;
1809

    
1810
constructor:
1811
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
1812
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
1813
 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
1814
 ;
1815

    
1816

    
1817
/*
1818
 *  Maybe there are no dynamic attributes defined by protocols.
1819
 *  For such cases, we force the dynamic_attr list to contain
1820
 *  at least an invalid token, so it is syntantically correct.
1821
 */
1822

    
1823
rtadot: /* EMPTY, we are not permitted RTA. prefix */
1824
 ;
1825

    
1826
function_call:
1827
   SYM '(' var_list ')' {
1828
     struct symbol *sym;
1829
     struct f_inst *inst = $3;
1830
     if ($1->class != SYM_FUNCTION)
1831
       cf_error("You can't call something which is not a function. Really.");
1832
     DBG("You are calling function %s\n", $1->name);
1833
     $$ = f_new_inst();
1834
     $$->code = P('c','a');
1835
     $$->a1.p = inst;
1836
     $$->a2.p = $1->def;
1837
     sym = $1->aux2;
1838
     while (sym || inst) {
1839
       if (!sym || !inst)
1840
	 cf_error("Wrong number of arguments for function %s.", $1->name);
1841
       DBG( "You should pass parameter called %s\n", sym->name);
1842
       inst->a1.p = sym;
1843
       sym = sym->aux2;
1844
       inst = inst->next;
1845
     }
1846
   }
1847
 ;
1848

    
1849
symbol:
1850
   SYM {
1851
     $$ = f_new_inst();
1852

    
1853
     switch ($1->class & 0xff00) {
1854
       case SYM_CONSTANT: $$->code = 'C'; break;
1855
       case SYM_VARIABLE: $$->code = 'V'; break;
1856
       default: cf_error("%s: variable expected.", $1->name);
1857
     }
1858

    
1859
     $$->a1.p = $1->def;
1860
     $$->a2.p = $1->name;
1861
   }
1862

    
1863
static_attr:
1864
   FROM    { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_FROM;	$$->a1.i = 1; }
1865
 | GW      { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_GW;	$$->a1.i = 1; }
1866
 | NET     { $$ = f_new_inst(); $$->aux = T_NET;        $$->a2.i = SA_NET; }
1867
 | PROTO   { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = SA_PROTO; }
1868
 | SOURCE  { $$ = f_new_inst(); $$->aux = T_ENUM_RTS;   $$->a2.i = SA_SOURCE; }
1869
 | SCOPE   { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE;	$$->a1.i = 1; }
1870
 | DEST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTD;   $$->a2.i = SA_DEST;	$$->a1.i = 1; }
1871
 | IFNAME  { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = SA_IFNAME; }
1872
 | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT;        $$->a2.i = SA_IFINDEX; }
1873
 ;
1874

    
1875
term:
1876
   '(' term ')'      { $$ = $2; }
1877
 | term '+' term     { $$ = f_new_inst(); $$->code = '+';        $$->a1.p = $1; $$->a2.p = $3; }
1878
 | term '-' term     { $$ = f_new_inst(); $$->code = '-';        $$->a1.p = $1; $$->a2.p = $3; }
1879
 | term '*' term     { $$ = f_new_inst(); $$->code = '*';        $$->a1.p = $1; $$->a2.p = $3; }
1880
 | term '/' term     { $$ = f_new_inst(); $$->code = '/';        $$->a1.p = $1; $$->a2.p = $3; }
1881
 | term AND term     { $$ = f_new_inst(); $$->code = '&';        $$->a1.p = $1; $$->a2.p = $3; }
1882
 | term OR  term     { $$ = f_new_inst(); $$->code = '|';        $$->a1.p = $1; $$->a2.p = $3; }
1883
 | term '=' term     { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
1884
 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','=');     $$->a1.p = $1; $$->a2.p = $3; }
1885
 | term '<' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $1; $$->a2.p = $3; }
1886
 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $1; $$->a2.p = $3; }
1887
 | term '>' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $3; $$->a2.p = $1; }
1888
 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $3; $$->a2.p = $1; }
1889
 | term '~' term     { $$ = f_new_inst(); $$->code = '~';        $$->a1.p = $1; $$->a2.p = $3; }
1890
 | term NMA term { $$ = f_new_inst(); $$->code = P('!','~');     $$->a1.p = $1; $$->a2.p = $3; }
1891
 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
1892
 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e');  $$->a1.p = $3; }
1893

    
1894
 | symbol   { $$ = $1; }
1895
 | constant { $$ = $1; }
1896
 | constructor { $$ = $1; }
1897

    
1898
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
1899

    
1900
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
1901

    
1902
 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
1903

    
1904
 | term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; }
1905
 | term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; }
1906
 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
1907
 | term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; }
1908
 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
1909
 | term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; }
1910
 | term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; }
1911
 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
1912
 | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
1913
 | term '.' LAST  { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
1914
 | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
1915

    
1916
/* Communities */
1917
/* This causes one shift/reduce conflict
1918
 | rtadot dynamic_attr '.' ADD '(' term ')' { }
1919
 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
1920
 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
1921
 | rtadot dynamic_attr '.' RESET{ }
1922
*/
1923

    
1924
 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
1925
 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
1926
 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
1927
 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
1928
 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
1929
 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
1930
 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
1931
 | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
1932

    
1933
 | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
1934
 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
1935

    
1936
 | FORMAT '(' term ')' {  $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; }
1937

    
1938
/* | term '.' LEN { $$->code = P('P','l'); } */
1939

    
1940
/* function_call is inlined here */
1941
 | SYM '(' var_list ')' {
1942
     struct symbol *sym;
1943
     struct f_inst *inst = $3;
1944
     if ($1->class != SYM_FUNCTION)
1945
       cf_error("You can't call something which is not a function. Really.");
1946
     DBG("You are calling function %s\n", $1->name);
1947
     $$ = f_new_inst();
1948
     $$->code = P('c','a');
1949
     $$->a1.p = inst;
1950
     $$->a2.p = $1->def;
1951
     sym = $1->aux2;
1952
     while (sym || inst) {
1953
       if (!sym || !inst)
1954
	 cf_error("Wrong number of arguments for function %s.", $1->name);
1955
       DBG( "You should pass parameter called %s\n", sym->name);
1956
       inst->a1.p = sym;
1957
       sym = sym->aux2;
1958
       inst = inst->next;
1959
     }
1960
   }
1961
 ;
1962

    
1963
break_command:
1964
   QUITBIRD { $$ = F_QUITBIRD; }
1965
 | ACCEPT { $$ = F_ACCEPT; }
1966
 | REJECT { $$ = F_REJECT; }
1967
 | ERROR { $$ = F_ERROR; }
1968
 | PRINT { $$ = F_NOP; }
1969
 | PRINTN { $$ = F_NONL; }
1970
 ;
1971

    
1972
print_one:
1973
   term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
1974
 ;
1975

    
1976
print_list: /* EMPTY */ { $$ = NULL; }
1977
 | print_one { $$ = $1; }
1978
 | print_one ',' print_list {
1979
     if ($1) {
1980
       $1->next = $3;
1981
       $$ = $1;
1982
     } else $$ = $3;
1983
   }
1984
 ;
1985

    
1986
var_listn: term {
1987
     $$ = f_new_inst();
1988
     $$->code = 's';
1989
     $$->a1.p = NULL;
1990
     $$->a2.p = $1;
1991
     $$->next = NULL;
1992
   }
1993
 | term ',' var_listn {
1994
     $$ = f_new_inst();
1995
     $$->code = 's';
1996
     $$->a1.p = NULL;
1997
     $$->a2.p = $1;
1998
     $$->next = $3;
1999
   }
2000
 ;
2001

    
2002
var_list: /* EMPTY */ { $$ = NULL; }
2003
 | var_listn { $$ = $1; }
2004
 ;
2005

    
2006
cmd:
2007
   IF term THEN block {
2008
     $$ = f_new_inst();
2009
     $$->code = '?';
2010
     $$->a1.p = $2;
2011
     $$->a2.p = $4;
2012
   }
2013
 | IF term THEN block ELSE block {
2014
     struct f_inst *i = f_new_inst();
2015
     i->code = '?';
2016
     i->a1.p = $2;
2017
     i->a2.p = $4;
2018
     $$ = f_new_inst();
2019
     $$->code = '?';
2020
     $$->a1.p = i;
2021
     $$->a2.p = $6;
2022
   }
2023
 | SYM '=' term ';' {
2024
     $$ = f_new_inst();
2025
     DBG( "Ook, we'll set value\n" );
2026
     if (($1->class & ~T_MASK) != SYM_VARIABLE)
2027
       cf_error( "You may set only variables." );
2028
     $$->code = 's';
2029
     $$->a1.p = $1;
2030
     $$->a2.p = $3;
2031
   }
2032
 | RETURN term ';' {
2033
     $$ = f_new_inst();
2034
     DBG( "Ook, we'll return the value\n" );
2035
     $$->code = 'r';
2036
     $$->a1.p = $2;
2037
   }
2038
 | rtadot dynamic_attr '=' term ';' {
2039
     $$ = $2;
2040
     $$->code = P('e','S');
2041
     $$->a1.p = $4;
2042
   }
2043
 | rtadot static_attr '=' term ';' {
2044
     $$ = $2;
2045
     if (!$$->a1.i)
2046
       cf_error( "This static attribute is read-only.");
2047
     $$->code = P('a','S');
2048
     $$->a1.p = $4;
2049
   }
2050
 | PREFERENCE '=' term ';' {
2051
     $$ = f_new_inst();
2052
     $$->code = P('P','S');
2053
     $$->a1.p = $3;
2054
   }
2055
 | UNSET '(' rtadot dynamic_attr ')' ';' {
2056
     $$ = $4;
2057
     $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
2058
     $$->code = P('e','S');
2059
     $$->a1.p = NULL;
2060
   }
2061
 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
2062
 | function_call ';' { $$ = $1; }
2063
 | CASE term '{' switch_body '}' {
2064
      $$ = f_new_inst();
2065
      $$->code = P('S','W');
2066
      $$->a1.p = $2;
2067
      $$->a2.p = build_tree( $4 );
2068
   }
2069

    
2070
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
2071
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
2072
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
2073
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
2074
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
2075
 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
2076
 ;
2077

    
2078
get_cf_position:
2079
{
2080
  $$ = cf_text;
2081
};
2082

    
2083

    
2084
/* Grammar from nest/config.Y */
2085

    
2086
/* Setting of router ID */
2087

    
2088

    
2089
rtrid:
2090
   ROUTER ID idval ';' { new_config->router_id = $3; }
2091
 | ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; }
2092
 ;
2093

    
2094
idval:
2095
   NUM { $$ = $1; }
2096
 | '(' term ')' { $$ = f_eval_int($2); }
2097
 | IP4 { $$ = ip4_to_u32($1); }
2098
 | SYM {
2099
     if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
2100
       $$ = SYM_VAL($1).i;
2101
     else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
2102
       $$ = ipa_to_u32(SYM_VAL($1).ip);
2103
     else
2104
       cf_error("Number or IPv4 address constant expected");
2105
   }
2106
 ;
2107

    
2108

    
2109
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
2110

    
2111

    
2112
/* Network types (for tables, channels) */
2113

    
2114
net_type:
2115
   IPV4 { $$ = NET_IP4; }
2116
 | IPV6 { $$ = NET_IP6; }
2117
 | VPN4 { $$ = NET_VPN4; }
2118
 | VPN6 { $$ = NET_VPN6; }
2119
 | ROA4 { $$ = NET_ROA4; }
2120
 | ROA6 { $$ = NET_ROA6; }
2121
 | FLOW4{ $$ = NET_FLOW4; }
2122
 | FLOW6{ $$ = NET_FLOW6; }
2123
 | MPLS { $$ = NET_MPLS; }
2124
 ;
2125

    
2126

    
2127

    
2128

    
2129
/* Creation of routing tables */
2130

    
2131

    
2132
table_sorted:
2133
          { $$ = 0; }
2134
 | SORTED { $$ = 1; }
2135
 ;
2136

    
2137
table: net_type TABLE SYM table_sorted {
2138
   struct rtable_config *cf;
2139
   cf = rt_new_table($3, $1);
2140
   cf->sorted = $4;
2141
   }
2142
 ;
2143

    
2144

    
2145
/* Definition of protocols */
2146

    
2147

    
2148
proto_start:
2149
   PROTOCOL { $$ = SYM_PROTO; }
2150
 | TEMPLATE { $$ = SYM_TEMPLATE; }
2151
 ;
2152

    
2153
proto_name:
2154
   /* EMPTY */ {
2155
     struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
2156
     s->class = this_proto->class;
2157
     s->def = this_proto;
2158
     this_proto->name = s->name;
2159
     }
2160
 | SYM {
2161
     cf_define_symbol($1, this_proto->class, this_proto);
2162
     this_proto->name = $1->name;
2163
   }
2164
 | FROM SYM {
2165
     struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
2166
     s->class = this_proto->class;
2167
     s->def = this_proto;
2168
     this_proto->name = s->name;
2169

    
2170
     if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
2171
     proto_copy_config(this_proto, $2->def);
2172
   }
2173
 | SYM FROM SYM {
2174
     cf_define_symbol($1, this_proto->class, this_proto);
2175
     this_proto->name = $1->name;
2176

    
2177
     if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
2178
     proto_copy_config(this_proto, $3->def);
2179
   }
2180
 ;
2181

    
2182
proto_item:
2183
   /* EMPTY */
2184
 | DISABLED bool { this_proto->disabled = $2; }
2185
 | DEBUG debug_mask { this_proto->debug = $2; }
2186
 | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
2187
 | ROUTER ID idval { this_proto->router_id = $3; }
2188
 | DESCRIPTION text { this_proto->dsc = $2; }
2189
 | VRF text { this_proto->vrf = if_get_by_name($2); }
2190
 ;
2191

    
2192

    
2193
channel_start: net_type
2194
{
2195
  $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
2196
};
2197

    
2198
channel_item:
2199
   TABLE rtable {
2200
     if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
2201
       cf_error("Incompatible table type");
2202
     this_channel->table = $2;
2203
   }
2204
 | IMPORT imexport { this_channel->in_filter = $2; }
2205
 | EXPORT imexport { this_channel->out_filter = $2; }
2206
 | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
2207
 | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
2208
 | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
2209
 | PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
2210
 | IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
2211
 ;
2212

    
2213
channel_opts:
2214
   /* empty */
2215
 | channel_opts channel_item ';'
2216
 ;
2217

    
2218
channel_opt_list:
2219
   /* empty */
2220
 | '{' channel_opts '}'
2221
 ;
2222

    
2223
channel_end:
2224
{
2225
  if (!this_channel->table)
2226
    cf_error("Routing table not specified");
2227

    
2228
  this_channel = NULL;
2229
};
2230

    
2231
proto_channel: channel_start channel_opt_list channel_end;
2232

    
2233

    
2234
rtable:
2235
   SYM {
2236
     if ($1->class != SYM_TABLE) cf_error("Table expected");
2237
     $$ = $1->def;
2238
   }
2239
 ;
2240

    
2241
imexport:
2242
   FILTER filter { $$ = $2; }
2243
 | where_filter
2244
 | ALL { $$ = FILTER_ACCEPT; }
2245
 | NONE { $$ = FILTER_REJECT; }
2246
 ;
2247

    
2248
limit_action:
2249
   /* default */ { $$ = PLA_DISABLE; }
2250
 | ACTION WARN { $$ = PLA_WARN; }
2251
 | ACTION BLOCK { $$ = PLA_BLOCK; }
2252
 | ACTION RESTART { $$ = PLA_RESTART; }
2253
 | ACTION DISABLE { $$ = PLA_DISABLE; }
2254
 ;
2255

    
2256
limit_spec:
2257
   expr limit_action { $$ = (struct channel_limit){ .limit = $1, $$.action = $2 }; }
2258
 | OFF { $$ = (struct channel_limit){}; }
2259
 ;
2260

    
2261

    
2262

    
2263
debug_default:
2264
   DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
2265
 | DEBUG COMMANDS expr { new_config->cli_debug = $3; }
2266
 ;
2267

    
2268
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
2269

    
2270

    
2271
timeformat_which:
2272
   ROUTE { $$ = &new_config->tf_route; }
2273
 | PROTOCOL { $$ = &new_config->tf_proto; }
2274
 | BASE { $$ = &new_config->tf_base; }
2275
 | LOG { $$ = &new_config->tf_log; }
2276
 ;
2277

    
2278
timeformat_spec:
2279
   timeformat_which TEXT { *$1 = (struct timeformat){$2, NULL, 0}; }
2280
 | timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, (s64) $3 S_}; }
2281
 | timeformat_which ISO SHORT    { *$1 = TM_ISO_SHORT_S; }
2282
 | timeformat_which ISO SHORT MS { *$1 = TM_ISO_SHORT_MS; }
2283
 | timeformat_which ISO SHORT US { *$1 = TM_ISO_SHORT_US; }
2284
 | timeformat_which ISO LONG    { *$1 = TM_ISO_LONG_S; }
2285
 | timeformat_which ISO LONG MS { *$1 = TM_ISO_LONG_MS; }
2286
 | timeformat_which ISO LONG US { *$1 = TM_ISO_LONG_US; }
2287
 ;
2288

    
2289
timeformat_base:
2290
   TIMEFORMAT timeformat_spec ';'
2291
 ;
2292

    
2293

    
2294
/* Interface patterns */
2295

    
2296
iface_patt_node_init:
2297
   /* EMPTY */ {
2298
     struct iface_patt_node *ipn = cfg_allocz(sizeof(struct iface_patt_node));
2299
     add_tail(&this_ipatt->ipn_list, NODE ipn);
2300
     this_ipn = ipn;
2301
   }
2302
 ;
2303

    
2304
iface_patt_node_body:
2305
   TEXT { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ }
2306
 | opttext net_or_ipa { this_ipn->pattern = $1; this_ipn->prefix = $2; }
2307
 ;
2308

    
2309
iface_negate:
2310
       { this_ipn->positive = 1; }
2311
 | '-' { this_ipn->positive = 0; }
2312
 ;
2313

    
2314
iface_patt_node:
2315
   iface_patt_node_init iface_negate iface_patt_node_body
2316
 ;
2317

    
2318

    
2319
iface_patt_list:
2320
   iface_patt_node
2321
 | iface_patt_list ',' iface_patt_node
2322
 ;
2323

    
2324
/* For name/mask-only iface patterns */
2325
iface_patt_list_nopx: iface_patt_list { iface_patt_check(); }
2326

    
2327
iface_patt_init: {
2328
   /* Generic this_ipatt init */
2329
   this_ipatt = cfg_allocz(sizeof(struct iface_patt));
2330
   init_list(&this_ipatt->ipn_list);
2331
 }
2332
 ;
2333

    
2334
iface_patt:
2335
   iface_patt_init iface_patt_list
2336
 ;
2337

    
2338
tos:
2339
   CLASS expr { $$ = $2 & 0xfc;        if ($2 > 255) cf_error("TX class must be in range 0-255"); }
2340
 | DSCP expr  { $$ = ($2 & 0x3f) << 2; if ($2 > 63)  cf_error("TX DSCP must be in range 0-63"); }
2341
 ;
2342

    
2343
/* Direct device route protocol */
2344

    
2345

    
2346
dev_proto_start: proto_start DIRECT {
2347
     this_proto = proto_config_new(&proto_device, $1);
2348
     init_list(&DIRECT_CFG->iface_list);
2349
   }
2350
 ;
2351

    
2352
dev_proto:
2353
   dev_proto_start proto_name '{'
2354
 | dev_proto proto_item ';'
2355
 | dev_proto proto_channel ';'
2356
 | dev_proto dev_iface_patt ';'
2357
 | dev_proto CHECK LINK bool ';' { DIRECT_CFG->check_link = $4; }
2358
 ;
2359

    
2360
dev_iface_init:
2361
   /* EMPTY */ {
2362
     this_ipatt = cfg_allocz(sizeof(struct iface_patt));
2363
     add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt);
2364
     init_list(&this_ipatt->ipn_list);
2365
   }
2366
 ;
2367

    
2368
dev_iface_patt:
2369
   INTERFACE dev_iface_init iface_patt_list
2370
 ;
2371

    
2372
/* Debug flags */
2373

    
2374
debug_mask:
2375
   ALL { $$ = ~0; }
2376
 | OFF { $$ = 0; }
2377
 | '{' debug_list '}' { $$ = $2; }
2378
 ;
2379

    
2380
debug_list:
2381
   debug_flag
2382
 | debug_list ',' debug_flag { $$ = $1 | $3; }
2383
 ;
2384

    
2385
debug_flag:
2386
   STATES	{ $$ = D_STATES; }
2387
 | ROUTES	{ $$ = D_ROUTES; }
2388
 | FILTERS	{ $$ = D_FILTERS; }
2389
 | INTERFACES	{ $$ = D_IFACES; }
2390
 | EVENTS	{ $$ = D_EVENTS; }
2391
 | PACKETS	{ $$ = D_PACKETS; }
2392
 ;
2393

    
2394
/* MRTDump flags */
2395

    
2396
mrtdump_mask:
2397
   ALL { $$ = ~0; }
2398
 | OFF { $$ = 0; }
2399
 | '{' mrtdump_list '}' { $$ = $2; }
2400
 ;
2401

    
2402
mrtdump_list:
2403
   mrtdump_flag
2404
 | mrtdump_list ',' mrtdump_flag { $$ = $1 | $3; }
2405
 ;
2406

    
2407
mrtdump_flag:
2408
   STATES	{ $$ = MD_STATES; }
2409
 | MESSAGES	{ $$ = MD_MESSAGES; }
2410
 ;
2411

    
2412
/* Password lists */
2413

    
2414
password_list:
2415
   PASSWORDS '{' password_items '}'
2416
 | password_item
2417
;
2418

    
2419
password_items:
2420
    /* empty */
2421
  | password_item ';' password_items
2422
;
2423

    
2424
password_item:
2425
    password_item_begin '{' password_item_params '}'
2426
  | password_item_begin
2427
;
2428

    
2429
password_item_begin:
2430
   PASSWORD text {
2431
     if (!this_p_list) {
2432
     	this_p_list = cfg_alloc(sizeof(list));
2433
     	init_list(this_p_list);
2434
        password_id = 1;
2435
     }
2436
     this_p_item = cfg_alloc(sizeof (struct password_item));
2437
     this_p_item->password = $2;
2438
     this_p_item->length = strlen($2);
2439
     this_p_item->genfrom = 0;
2440
     this_p_item->gento = TIME_INFINITY;
2441
     this_p_item->accfrom = 0;
2442
     this_p_item->accto = TIME_INFINITY;
2443
     this_p_item->id = password_id++;
2444
     this_p_item->alg = ALG_UNDEFINED;
2445
     add_tail(this_p_list, &this_p_item->n);
2446
   }
2447
;
2448

    
2449
password_item_params:
2450
   /* empty */ { }
2451
 | GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
2452
 | GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
2453
 | ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
2454
 | ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
2455
 | FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
2456
 | TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
2457
 | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
2458
 | ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
2459
 ;
2460

    
2461
password_algorithm:
2462
   KEYED MD5	{ $$ = ALG_MD5; }
2463
 | KEYED SHA1	{ $$ = ALG_SHA1; }
2464
 | KEYED SHA256	{ $$ = ALG_SHA256; }
2465
 | KEYED SHA384	{ $$ = ALG_SHA384; }
2466
 | KEYED SHA512	{ $$ = ALG_SHA512; }
2467
 | HMAC MD5	{ $$ = ALG_HMAC_MD5; }
2468
 | HMAC SHA1	{ $$ = ALG_HMAC_SHA1; }
2469
 | HMAC SHA256	{ $$ = ALG_HMAC_SHA256; }
2470
 | HMAC SHA384	{ $$ = ALG_HMAC_SHA384; }
2471
 | HMAC SHA512	{ $$ = ALG_HMAC_SHA512; }
2472
 ;
2473

    
2474
/* Core commands */
2475

    
2476

    
2477
cmd_SHOW_STATUS: SHOW STATUS  END
2478
{ cmd_show_status(); } ;
2479

    
2480
cmd_SHOW_MEMORY: SHOW MEMORY  END
2481
{ cmd_show_memory(); } ;
2482

    
2483
cmd_SHOW_PROTOCOLS: SHOW PROTOCOLS proto_patt2 END
2484
{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
2485

    
2486
cmd_SHOW_PROTOCOLS_ALL: SHOW PROTOCOLS ALL proto_patt2 END
2487
{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
2488

    
2489
optsym:
2490
   SYM
2491
 | /* empty */ { $$ = NULL; }
2492
 ;
2493

    
2494
cmd_SHOW_INTERFACES: SHOW INTERFACES  END
2495
{ if_show(); } ;
2496

    
2497
cmd_SHOW_INTERFACES_SUMMARY: SHOW INTERFACES SUMMARY  END
2498
{ if_show_summary(); } ;
2499

    
2500

    
2501
cmd_SHOW_ROUTE: SHOW ROUTE r_args END
2502
{ rt_show($3); } ;
2503

    
2504
r_args:
2505
   /* empty */ {
2506
     $$ = cfg_allocz(sizeof(struct rt_show_data));
2507
     init_list(&($$->tables));
2508
     $$->filter = FILTER_ACCEPT;
2509
   }
2510
 | r_args net_any {
2511
     $$ = $1;
2512
     if ($$->addr) cf_error("Only one prefix expected");
2513
     $$->addr = $2;
2514
   }
2515
 | r_args FOR r_args_for {
2516
     $$ = $1;
2517
     if ($$->addr) cf_error("Only one prefix expected");
2518
     $$->show_for = 1;
2519
     $$->addr = $3;
2520
   }
2521
 | r_args TABLE SYM {
2522
     $$ = $1;
2523
     if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name);
2524
     rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
2525
     $$->tables_defined_by = RSD_TDB_DIRECT;
2526
   }
2527
 | r_args TABLE ALL {
2528
     struct rtable_config *t;
2529
     $$ = $1;
2530
     WALK_LIST(t, config->tables)
2531
       rt_show_add_table($$, t->table);
2532
     $$->tables_defined_by = RSD_TDB_ALL;
2533
   }
2534
 | r_args FILTER filter {
2535
     $$ = $1;
2536
     if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
2537
     $$->filter = $3;
2538
   }
2539
 | r_args where_filter {
2540
     $$ = $1;
2541
     if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
2542
     $$->filter = $2;
2543
   }
2544
 | r_args ALL {
2545
     $$ = $1;
2546
     $$->verbose = 1;
2547
   }
2548
 | r_args PRIMARY {
2549
     $$ = $1;
2550
     $$->primary_only = 1;
2551
   }
2552
 | r_args FILTERED {
2553
     $$ = $1;
2554
     $$->filtered = 1;
2555
   }
2556
 | r_args export_mode SYM {
2557
     struct proto_config *c = (struct proto_config *) $3->def;
2558
     $$ = $1;
2559
     if ($$->export_mode) cf_error("Export specified twice");
2560
     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
2561
     $$->export_mode = $2;
2562
     $$->export_protocol = c->proto;
2563
     $$->running_on_config = c->proto->cf->global;
2564
     $$->tables_defined_by = RSD_TDB_INDIRECT;
2565
   }
2566
 | r_args export_mode SYM '.' r_args_channel {
2567
     struct proto_config *c = (struct proto_config *) $3->def;
2568
     $$ = $1;
2569
     if ($$->export_mode) cf_error("Export specified twice");
2570
     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
2571
     $$->export_mode = $2;
2572
     $$->export_channel = proto_find_channel_by_name(c->proto, $5);
2573
     if (!$$->export_channel) cf_error("Export channel not found");
2574
     $$->running_on_config = c->proto->cf->global;
2575
     $$->tables_defined_by = RSD_TDB_INDIRECT;
2576
   }
2577
 | r_args PROTOCOL SYM {
2578
     struct proto_config *c = (struct proto_config *) $3->def;
2579
     $$ = $1;
2580
     if ($$->show_protocol) cf_error("Protocol specified twice");
2581
     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
2582
     $$->show_protocol = c->proto;
2583
     $$->running_on_config = c->proto->cf->global;
2584
     $$->tables_defined_by = RSD_TDB_INDIRECT;
2585
   }
2586
 | r_args STATS {
2587
     $$ = $1;
2588
     $$->stats = 1;
2589
   }
2590
 | r_args COUNT {
2591
     $$ = $1;
2592
     $$->stats = 2;
2593
   }
2594
 ;
2595

    
2596
r_args_for:
2597
  r_args_for_val {
2598
    $$ = cfg_alloc($1.length);
2599
    net_copy($$, &$1);
2600
  }
2601
 | net_vpn4_
2602
 | net_vpn6_
2603
 | VPN_RD IP4 {
2604
    $$ = cfg_alloc(sizeof(net_addr_vpn4));
2605
    net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1);
2606
  }
2607
 | VPN_RD IP6 {
2608
    $$ = cfg_alloc(sizeof(net_addr_vpn6));
2609
    net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1);
2610
  }
2611
 | SYM {
2612
     if ($1->class == (SYM_CONSTANT | T_IP))
2613
     {
2614
       $$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
2615
       net_fill_ip_host($$, SYM_VAL($1).ip);
2616
     }
2617
     else if (($1->class == (SYM_CONSTANT | T_NET)) && net_type_match(SYM_VAL($1).net, NB_IP | NB_VPN))
2618
       $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
2619
     else
2620
       cf_error("IP address or network expected");
2621
   }
2622
 ;
2623

    
2624
r_args_for_val:
2625
   net_ip4_
2626
 | net_ip6_
2627
 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
2628
 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }
2629

    
2630
export_mode:
2631
   PREEXPORT	{ $$ = RSEM_PREEXPORT; }
2632
 | EXPORT	{ $$ = RSEM_EXPORT; }
2633
 | NOEXPORT	{ $$ = RSEM_NOEXPORT; }
2634
 ;
2635

    
2636
/* This is ugly hack */
2637
r_args_channel:
2638
   IPV4		{ $$ = "ipv4"; }
2639
 | IPV4_MC	{ $$ = "ipv4-mc"; }
2640
 | IPV4_MPLS	{ $$ = "ipv4-mpls"; }
2641
 | IPV6		{ $$ = "ipv6"; }
2642
 | IPV6_MC	{ $$ = "ipv6-mc"; }
2643
 | IPV6_MPLS	{ $$ = "ipv6-mpls"; }
2644
 | VPN4		{ $$ = "vpn4"; }
2645
 | VPN4_MC	{ $$ = "vpn4-mc"; }
2646
 | VPN4_MPLS	{ $$ = "vpn4-mpls"; }
2647
 | VPN6		{ $$ = "vpn6"; }
2648
 | VPN6_MC	{ $$ = "vpn6-mc"; }
2649
 | VPN6_MPLS	{ $$ = "vpn6-mpls"; }
2650
 | ROA4		{ $$ = "roa4"; }
2651
 | ROA6		{ $$ = "roa6"; }
2652
 | FLOW4	{ $$ = "flow4"; }
2653
 | FLOW6	{ $$ = "flow6"; }
2654
 | MPLS		{ $$ = "mpls"; }
2655
 | PRI		{ $$ = "pri"; }
2656
 | SEC		{ $$ = "sec"; }
2657
 ;
2658

    
2659

    
2660
cmd_SHOW_SYMBOLS: SHOW SYMBOLS sym_args END
2661
{ cmd_show_symbols($3); } ;
2662

    
2663
sym_args:
2664
   /* empty */ {
2665
     $$ = cfg_allocz(sizeof(struct sym_show_data));
2666
   }
2667
 | sym_args TABLE { $$ = $1; $$->type = SYM_TABLE; }
2668
 | sym_args FUNCTION { $$ = $1; $$->type = SYM_FUNCTION; }
2669
 | sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
2670
 | sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
2671
 | sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
2672
 | sym_args SYM { $$ = $1; $$->sym = $2; }
2673
 ;
2674

    
2675

    
2676

    
2677
cmd_DUMP_RESOURCES: DUMP RESOURCES  END
2678
{ rdump(&root_pool); cli_msg(0, ""); } ;
2679
cmd_DUMP_SOCKETS: DUMP SOCKETS  END
2680
{ sk_dump_all(); cli_msg(0, ""); } ;
2681
cmd_DUMP_EVENTS: DUMP EVENTS  END
2682
{ io_log_dump(); cli_msg(0, ""); } ;
2683
cmd_DUMP_INTERFACES: DUMP INTERFACES  END
2684
{ if_dump_all(); cli_msg(0, ""); } ;
2685
cmd_DUMP_NEIGHBORS: DUMP NEIGHBORS  END
2686
{ neigh_dump_all(); cli_msg(0, ""); } ;
2687
cmd_DUMP_ATTRIBUTES: DUMP ATTRIBUTES  END
2688
{ rta_dump_all(); cli_msg(0, ""); } ;
2689
cmd_DUMP_ROUTES: DUMP ROUTES  END
2690
{ rt_dump_all(); cli_msg(0, ""); } ;
2691
cmd_DUMP_PROTOCOLS: DUMP PROTOCOLS  END
2692
{ protos_dump_all(); cli_msg(0, ""); } ;
2693

    
2694
cmd_EVAL: EVAL term END
2695
{ cmd_eval($2); } ;
2696

    
2697

    
2698
cmd_ECHO: ECHO echo_mask echo_size END {
2699
  cli_set_log_echo(this_cli, $2, $3);
2700
  cli_msg(0, "");
2701
} ;
2702

    
2703
echo_mask:
2704
   ALL { $$ = ~0; }
2705
 | OFF { $$ = 0; }
2706
 | '{' log_mask_list '}' { $$ = $2; }
2707
 ;
2708

    
2709
echo_size:
2710
   /* empty */ { $$ = 4096; }
2711
 | NUM {
2712
     if ($1 < 256 || $1 > 65536) cf_error("Invalid log buffer size");
2713
     $$ = $1;
2714
   }
2715
 ;
2716

    
2717
cmd_DISABLE: DISABLE proto_patt opttext END
2718
{ proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
2719
cmd_ENABLE: ENABLE proto_patt opttext END
2720
{ proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
2721
cmd_RESTART: RESTART proto_patt opttext END
2722
{ proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
2723
cmd_RELOAD: RELOAD proto_patt END
2724
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
2725
cmd_RELOAD_IN: RELOAD IN proto_patt END
2726
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
2727
cmd_RELOAD_OUT: RELOAD OUT proto_patt END
2728
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
2729

    
2730

    
2731
cmd_DEBUG: DEBUG proto_patt debug_mask END
2732
{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
2733

    
2734

    
2735
cmd_MRTDUMP: MRTDUMP proto_patt mrtdump_mask END
2736
{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;
2737

    
2738
cmd_RESTRICT: RESTRICT  END
2739
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
2740

    
2741
proto_patt:
2742
   SYM  { $$.ptr = $1; $$.patt = 0; }
2743
 | ALL  { $$.ptr = NULL; $$.patt = 1; }
2744
 | TEXT { $$.ptr = $1; $$.patt = 1; }
2745
 ;
2746

    
2747
proto_patt2:
2748
   SYM  { $$.ptr = $1; $$.patt = 0; }
2749
 |      { $$.ptr = NULL; $$.patt = 1; }
2750
 | TEXT { $$.ptr = $1; $$.patt = 1; }
2751
 ;
2752

    
2753

    
2754

    
2755
/* Grammar from proto/bfd/config.Y */
2756

    
2757

    
2758
bfd_proto_start: proto_start BFD
2759
{
2760
  this_proto = proto_config_new(&proto_bfd, $1);
2761
  init_list(&BFD_CFG->patt_list);
2762
  init_list(&BFD_CFG->neigh_list);
2763

    
2764
  if (bfd_cf)
2765
    cf_error("Only one BFD instance allowed");
2766
  bfd_cf = BFD_CFG;
2767
};
2768

    
2769
bfd_proto_item:
2770
   proto_item
2771
 | INTERFACE bfd_iface
2772
 | MULTIHOP bfd_multihop
2773
 | NEIGHBOR bfd_neighbor
2774
 ;
2775

    
2776
bfd_proto_opts:
2777
   /* empty */
2778
 | bfd_proto_opts bfd_proto_item ';'
2779
 ;
2780

    
2781
bfd_proto:
2782
   bfd_proto_start proto_name '{' bfd_proto_opts '}';
2783

    
2784

    
2785
bfd_iface_start:
2786
{
2787
  this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config));
2788
  add_tail(&BFD_CFG->patt_list, NODE this_ipatt);
2789
  init_list(&this_ipatt->ipn_list);
2790

    
2791
  BFD_IFACE->min_rx_int = BFD_DEFAULT_MIN_RX_INT;
2792
  BFD_IFACE->min_tx_int = BFD_DEFAULT_MIN_TX_INT;
2793
  BFD_IFACE->idle_tx_int = BFD_DEFAULT_IDLE_TX_INT;
2794
  BFD_IFACE->multiplier = BFD_DEFAULT_MULTIPLIER;
2795

    
2796
  reset_passwords();
2797
};
2798

    
2799
bfd_iface_finish:
2800
{
2801
  BFD_IFACE->passwords = get_passwords();
2802

    
2803
  if (!BFD_IFACE->auth_type != !BFD_IFACE->passwords)
2804
    log(L_WARN "Authentication and password options should be used together");
2805

    
2806
  if (BFD_IFACE->passwords)
2807
  {
2808
    struct password_item *pass;
2809
    WALK_LIST(pass, *BFD_IFACE->passwords)
2810
    {
2811
      if (pass->alg)
2812
        cf_error("Password algorithm option not available in BFD protocol");
2813

    
2814
      pass->alg = bfd_auth_type_to_hash_alg[BFD_IFACE->auth_type];
2815
    }
2816
  }
2817
};
2818

    
2819
bfd_iface_item:
2820
   INTERVAL expr_us { BFD_IFACE->min_rx_int = BFD_IFACE->min_tx_int = $2; }
2821
 | MIN RX INTERVAL expr_us { BFD_IFACE->min_rx_int = $4; }
2822
 | MIN TX INTERVAL expr_us { BFD_IFACE->min_tx_int = $4; }
2823
 | IDLE TX INTERVAL expr_us { BFD_IFACE->idle_tx_int = $4; }
2824
 | MULTIPLIER expr { BFD_IFACE->multiplier = $2; }
2825
 | PASSIVE bool { BFD_IFACE->passive = $2; }
2826
 | AUTHENTICATION bfd_auth_type { BFD_IFACE->auth_type = $2; }
2827
 | password_list {}
2828
 ;
2829

    
2830
bfd_auth_type:
2831
   NONE			 { $$ = BFD_AUTH_NONE; }
2832
 | SIMPLE 		 { $$ = BFD_AUTH_SIMPLE; }
2833
 | KEYED MD5		 { $$ = BFD_AUTH_KEYED_MD5; }
2834
 | KEYED SHA1   	 { $$ = BFD_AUTH_KEYED_SHA1; }
2835
 | METICULOUS KEYED MD5	 { $$ = BFD_AUTH_METICULOUS_KEYED_MD5; }
2836
 | METICULOUS KEYED SHA1 { $$ = BFD_AUTH_METICULOUS_KEYED_SHA1; }
2837
 ;
2838

    
2839
bfd_iface_opts:
2840
   /* empty */
2841
 | bfd_iface_opts bfd_iface_item ';'
2842
 ;
2843

    
2844
bfd_iface_opt_list:
2845
   /* empty */
2846
 | '{' bfd_iface_opts '}'
2847
 ;
2848

    
2849
bfd_iface:
2850
  bfd_iface_start iface_patt_list_nopx bfd_iface_opt_list bfd_iface_finish;
2851

    
2852
bfd_multihop:
2853
  bfd_iface_start bfd_iface_opt_list bfd_iface_finish
2854
{ BFD_CFG->multihop = BFD_IFACE; };
2855

    
2856

    
2857
bfd_neigh_iface:
2858
   /* empty */ { $$ = NULL; }
2859
 | '%' SYM { $$ = if_get_by_name($2->name); }
2860
 | DEV text { $$ = if_get_by_name($2); }
2861
 ;
2862

    
2863
bfd_neigh_local:
2864
   /* empty */ { $$ = IPA_NONE; }
2865
 | LOCAL ipa { $$ = $2; }
2866
 ;
2867

    
2868
bfd_neigh_multihop:
2869
   /* empty */ { $$ = 0; }
2870
 | MULTIHOP bool { $$ = $2; }
2871
 ;
2872

    
2873
bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop
2874
{
2875
  this_bfd_neighbor = cfg_allocz(sizeof(struct bfd_neighbor));
2876
  add_tail(&BFD_CFG->neigh_list, NODE this_bfd_neighbor);
2877

    
2878
  BFD_NEIGHBOR->addr = $1;
2879
  BFD_NEIGHBOR->local = $3;
2880
  BFD_NEIGHBOR->iface = $2;
2881
  BFD_NEIGHBOR->multihop = $4;
2882

    
2883
  if ($4 && $2)
2884
    cf_error("Neighbor cannot set both interface and multihop");
2885

    
2886
  if ($4 && ipa_zero($3))
2887
    cf_error("Multihop neighbor requires specified local address");
2888
};
2889

    
2890

    
2891
;
2892
cmd_SHOW_BFD_SESSIONS: SHOW BFD SESSIONS optsym END
2893
{ bfd_show_sessions(proto_get_named($4, &proto_bfd)); };
2894

    
2895
/* Grammar from proto/babel/config.Y */
2896

    
2897

    
2898
babel_proto_start: proto_start BABEL
2899
{
2900
  this_proto = proto_config_new(&proto_babel, $1);
2901
  init_list(&BABEL_CFG->iface_list);
2902
  BABEL_CFG->hold_time = 1 S_;
2903
};
2904

    
2905
babel_proto_item:
2906
   proto_item
2907
 | proto_channel
2908
 | INTERFACE babel_iface
2909
 ;
2910

    
2911
babel_proto_opts:
2912
   /* empty */
2913
 | babel_proto_opts babel_proto_item ';'
2914
 ;
2915

    
2916
babel_proto:
2917
   babel_proto_start proto_name '{' babel_proto_opts '}';
2918

    
2919

    
2920
babel_iface_start:
2921
{
2922
  this_ipatt = cfg_allocz(sizeof(struct babel_iface_config));
2923
  add_tail(&BABEL_CFG->iface_list, NODE this_ipatt);
2924
  init_list(&this_ipatt->ipn_list);
2925
  BABEL_IFACE->port = BABEL_PORT;
2926
  BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
2927
  BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
2928
  BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
2929
  BABEL_IFACE->tx_priority = sk_priority_control;
2930
  BABEL_IFACE->check_link = 1;
2931
};
2932

    
2933

    
2934
babel_iface_finish:
2935
{
2936
  if (BABEL_IFACE->type == BABEL_IFACE_TYPE_WIRELESS)
2937
  {
2938
    if (!BABEL_IFACE->hello_interval)
2939
      BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRELESS;
2940
    if (!BABEL_IFACE->rxcost)
2941
      BABEL_IFACE->rxcost = BABEL_RXCOST_WIRELESS;
2942
  }
2943
  else
2944
  {
2945
    if (!BABEL_IFACE->hello_interval)
2946
      BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRED;
2947
    if (!BABEL_IFACE->rxcost)
2948
      BABEL_IFACE->rxcost = BABEL_RXCOST_WIRED;
2949
  }
2950

    
2951
  /* Make sure we do not overflow the 16-bit centisec fields */
2952
  if (!BABEL_IFACE->update_interval)
2953
    BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
2954
  BABEL_IFACE->ihu_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
2955

    
2956
  BABEL_CFG->hold_time = MAX_(BABEL_CFG->hold_time, BABEL_IFACE->update_interval*BABEL_HOLD_TIME_FACTOR);
2957
};
2958

    
2959

    
2960
babel_iface_item:
2961
 | PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
2962
 | RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
2963
 | LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
2964
 | TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
2965
 | TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
2966
 | HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); }
2967
 | UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Update interval must be in range 10 ms - 655 s"); }
2968
 | RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); }
2969
 | TX LENGTH expr { BABEL_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
2970
 | TX tos { BABEL_IFACE->tx_tos = $2; }
2971
 | TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; }
2972
 | CHECK LINK bool { BABEL_IFACE->check_link = $3; }
2973
 | NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error("Must be an IPv4 address"); }
2974
 | NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error("Must be an IPv6 address"); }
2975
 ;
2976

    
2977
babel_iface_opts:
2978
   /* empty */
2979
 | babel_iface_opts babel_iface_item ';'
2980
 ;
2981

    
2982
babel_iface_opt_list:
2983
   /* empty */
2984
 | '{' babel_iface_opts '}'
2985
 ;
2986

    
2987

    
2988
babel_iface:
2989
  babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish;
2990

    
2991

    
2992
;
2993

    
2994
cmd_SHOW_BABEL_INTERFACES: SHOW BABEL INTERFACES optsym opttext END
2995
{ babel_show_interfaces(proto_get_named($4, &proto_babel), $5); };
2996

    
2997
cmd_SHOW_BABEL_NEIGHBORS: SHOW BABEL NEIGHBORS optsym opttext END
2998
{ babel_show_neighbors(proto_get_named($4, &proto_babel), $5); };
2999

    
3000
cmd_SHOW_BABEL_ENTRIES: SHOW BABEL ENTRIES optsym opttext END
3001
{ babel_show_entries(proto_get_named($4, &proto_babel)); };
3002

    
3003
cmd_SHOW_BABEL_ROUTES: SHOW BABEL ROUTES optsym opttext END
3004
{ babel_show_routes(proto_get_named($4, &proto_babel)); };
3005

    
3006
/* Grammar from proto/bgp/config.Y */
3007

    
3008

    
3009
bgp_proto_start: proto_start BGP {
3010
     this_proto = proto_config_new(&proto_bgp, $1);
3011
     BGP_CFG->local_port = BGP_PORT;
3012
     BGP_CFG->remote_port = BGP_PORT;
3013
     BGP_CFG->multihop = -1;	/* undefined */
3014
     BGP_CFG->hold_time = 240;
3015
     BGP_CFG->initial_hold_time = 240;
3016
     BGP_CFG->compare_path_lengths = 1;
3017
     BGP_CFG->igp_metric = 1;
3018
     BGP_CFG->connect_delay_time = 5;
3019
     BGP_CFG->connect_retry_time = 120;
3020
     BGP_CFG->error_amnesia_time = 300;
3021
     BGP_CFG->error_delay_time_min = 60;
3022
     BGP_CFG->error_delay_time_max = 300;
3023
     BGP_CFG->enable_refresh = 1;
3024
     BGP_CFG->enable_as4 = 1;
3025
     BGP_CFG->capabilities = 2;
3026
     BGP_CFG->interpret_communities = 1;
3027
     BGP_CFG->default_local_pref = 100;
3028
     BGP_CFG->gr_mode = BGP_GR_AWARE;
3029
     BGP_CFG->gr_time = 120;
3030
     BGP_CFG->setkey = 1;
3031
     BGP_CFG->check_link = -1;
3032
   }
3033
 ;
3034

    
3035
bgp_loc_opts:
3036
   /* empty */
3037
 | bgp_loc_opts PORT expr { BGP_CFG->local_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); }
3038
 | bgp_loc_opts AS expr { BGP_CFG->local_as = $3; }
3039
 ;
3040

    
3041
bgp_nbr_opts:
3042
   /* empty */
3043
 | bgp_nbr_opts PORT expr { BGP_CFG->remote_port = $3; if (($3<1) || ($3>65535)) cf_error("Invalid port number"); }
3044
 | bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
3045
 ;
3046

    
3047
bgp_proto:
3048
   bgp_proto_start proto_name '{'
3049
 | bgp_proto proto_item ';'
3050
 | bgp_proto bgp_proto_channel ';'
3051
 | bgp_proto LOCAL bgp_loc_opts ';'
3052
 | bgp_proto LOCAL ipa ipa_scope bgp_loc_opts ';' {
3053
     BGP_CFG->local_ip = $3;
3054
     if ($4) BGP_CFG->iface = $4;
3055
   }
3056
 | bgp_proto NEIGHBOR bgp_nbr_opts ';'
3057
 | bgp_proto NEIGHBOR ipa ipa_scope bgp_nbr_opts ';' {
3058
     if (ipa_nonzero(BGP_CFG->remote_ip))
3059
       cf_error("Only one neighbor per BGP instance is allowed");
3060
     BGP_CFG->remote_ip = $3;
3061
     if ($4) BGP_CFG->iface = $4;
3062
   }
3063
 | bgp_proto INTERFACE TEXT ';' { BGP_CFG->iface = if_get_by_name($3); }
3064
 | bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; }
3065
 | bgp_proto RR CLIENT bool ';' { BGP_CFG->rr_client = $4; }
3066
 | bgp_proto RS CLIENT bool ';' { BGP_CFG->rs_client = $4; }
3067
 | bgp_proto CONFEDERATION expr ';' { BGP_CFG->confederation = $3; }
3068
 | bgp_proto CONFEDERATION MEMBER bool ';' { BGP_CFG->confederation_member = $4; }
3069
 | bgp_proto HOLD TIME expr ';' { BGP_CFG->hold_time = $4; }
3070
 | bgp_proto STARTUP HOLD TIME expr ';' { BGP_CFG->initial_hold_time = $5; }
3071
 | bgp_proto DIRECT ';' { BGP_CFG->multihop = 0; }
3072
 | bgp_proto MULTIHOP ';' { BGP_CFG->multihop = 64; }
3073
 | bgp_proto MULTIHOP expr ';' { BGP_CFG->multihop = $3; if (($3<1) || ($3>255)) cf_error("Multihop must be in range 1-255"); }
3074
 | bgp_proto STRICT BIND bool ';' { BGP_CFG->strict_bind = $4; }
3075
 | bgp_proto PATH METRIC bool ';' { BGP_CFG->compare_path_lengths = $4; }
3076
 | bgp_proto MED METRIC bool ';' { BGP_CFG->med_metric = $4; }
3077
 | bgp_proto IGP METRIC bool ';' { BGP_CFG->igp_metric = $4; }
3078
 | bgp_proto PREFER OLDER bool ';' { BGP_CFG->prefer_older = $4; }
3079
 | bgp_proto DETERMINISTIC MED bool ';' { BGP_CFG->deterministic_med = $4; }
3080
 | bgp_proto DEFAULT BGP_MED expr ';' { BGP_CFG->default_med = $4; }
3081
 | bgp_proto DEFAULT BGP_LOCAL_PREF expr ';' { BGP_CFG->default_local_pref = $4; }
3082
 | bgp_proto SOURCE ADDRESS ipa ';' { BGP_CFG->local_ip = $4; }
3083
 | bgp_proto START DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; log(L_WARN "%s: Start delay time option is deprecated, use connect delay time", this_proto->name); }
3084
 | bgp_proto CONNECT DELAY TIME expr ';' { BGP_CFG->connect_delay_time = $5; }
3085
 | bgp_proto CONNECT RETRY TIME expr ';' { BGP_CFG->connect_retry_time = $5; }
3086
 | bgp_proto KEEPALIVE TIME expr ';' { BGP_CFG->keepalive_time = $4; }
3087
 | bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; }
3088
 | bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
3089
 | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
3090
 | bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
3091
 | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
3092
 | bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
3093
 | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
3094
 | bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
3095
 | bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
3096
 | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
3097
 | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
3098
 | bgp_proto ALLOW LOCAL AS ';' { BGP_CFG->allow_local_as = -1; }
3099
 | bgp_proto ALLOW LOCAL AS expr ';' { BGP_CFG->allow_local_as = $5; }
3100
 | bgp_proto ALLOW BGP_LOCAL_PREF bool ';' { BGP_CFG->allow_local_pref = $4; }
3101
 | bgp_proto GRACEFUL RESTART bool ';' { BGP_CFG->gr_mode = $4; }
3102
 | bgp_proto GRACEFUL RESTART AWARE ';' { BGP_CFG->gr_mode = BGP_GR_AWARE; }
3103
 | bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; }
3104
 | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
3105
 | bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; }
3106
 | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
3107
 ;
3108

    
3109
bgp_afi:
3110
   IPV4			{ $$ = BGP_AF_IPV4; }
3111
 | IPV6			{ $$ = BGP_AF_IPV6; }
3112
 | IPV4 MULTICAST	{ $$ = BGP_AF_IPV4_MC; }
3113
 | IPV6 MULTICAST	{ $$ = BGP_AF_IPV6_MC; }
3114
 | IPV4 MPLS		{ $$ = BGP_AF_IPV4_MPLS; }
3115
 | IPV6 MPLS		{ $$ = BGP_AF_IPV6_MPLS; }
3116
 | VPN4 MPLS		{ $$ = BGP_AF_VPN4_MPLS; }
3117
 | VPN6 MPLS		{ $$ = BGP_AF_VPN6_MPLS; }
3118
 | VPN4 MULTICAST	{ $$ = BGP_AF_VPN4_MC; }
3119
 | VPN6 MULTICAST	{ $$ = BGP_AF_VPN6_MC; }
3120
 | FLOW4		{ $$ = BGP_AF_FLOW4; }
3121
 | FLOW6		{ $$ = BGP_AF_FLOW6; }
3122
 ;
3123

    
3124
bgp_channel_start: bgp_afi
3125
{
3126
  const struct bgp_af_desc *desc = bgp_get_af_desc($1);
3127

    
3128
  if (!desc)
3129
    cf_error("Unknown AFI/SAFI");
3130

    
3131
  this_channel = channel_config_get(&channel_bgp, desc->name, desc->net, this_proto);
3132

    
3133
  /* New channel */
3134
  if (!BGP_CC->desc)
3135
  {
3136
    BGP_CC->c.in_filter = FILTER_UNDEF;
3137
    BGP_CC->c.out_filter = FILTER_UNDEF;
3138
    BGP_CC->c.ra_mode = RA_UNDEF;
3139
    BGP_CC->afi = $1;
3140
    BGP_CC->desc = desc;
3141
    BGP_CC->gr_able = 0xff;	/* undefined */
3142
  }
3143
};
3144

    
3145
bgp_channel_item:
3146
   channel_item
3147
 | NEXT HOP ADDRESS ipa { BGP_CC->next_hop_addr = $4; }
3148
 | NEXT HOP SELF { BGP_CC->next_hop_self = 1; BGP_CC->next_hop_keep = 0; }
3149
 | NEXT HOP KEEP { BGP_CC->next_hop_keep = 1; BGP_CC->next_hop_self = 0; }
3150
 | MISSING LLADDR SELF { BGP_CC->missing_lladdr = MLL_SELF; }
3151
 | MISSING LLADDR DROP { BGP_CC->missing_lladdr = MLL_DROP; }
3152
 | MISSING LLADDR IGNORE { BGP_CC->missing_lladdr = MLL_IGNORE; }
3153
 | GATEWAY DIRECT { BGP_CC->gw_mode = GW_DIRECT; }
3154
 | GATEWAY RECURSIVE { BGP_CC->gw_mode = GW_RECURSIVE; }
3155
 | SECONDARY bool { BGP_CC->secondary = $2; }
3156
 | GRACEFUL RESTART bool { BGP_CC->gr_able = $3; }
3157
 | EXTENDED NEXT HOP bool { BGP_CC->ext_next_hop = $4; }
3158
 | ADD PATHS RX { BGP_CC->add_path = BGP_ADD_PATH_RX; }
3159
 | ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
3160
 | ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
3161
 | IGP TABLE rtable {
3162
    if (BGP_CC->desc->no_igp)
3163
      cf_error("IGP table not allowed here");
3164

    
3165
    if ($3->addr_type == NET_IP4)
3166
      BGP_CC->igp_table_ip4 = $3;
3167
    else if ($3->addr_type == NET_IP6)
3168
      BGP_CC->igp_table_ip6 = $3;
3169
    else
3170
      cf_error("Mismatched IGP table type");
3171
   }
3172
 ;
3173

    
3174
bgp_channel_opts:
3175
   /* empty */
3176
 | bgp_channel_opts bgp_channel_item ';'
3177
 ;
3178

    
3179
bgp_channel_opt_list:
3180
   /* empty */
3181
 | '{' bgp_channel_opts '}'
3182
 ;
3183

    
3184
bgp_channel_end:
3185
{
3186
  if (!this_channel->table)
3187
    cf_error("Routing table not specified");
3188

    
3189
  this_channel = NULL;
3190
};
3191

    
3192
bgp_proto_channel: bgp_channel_start bgp_channel_opt_list bgp_channel_end;
3193

    
3194

    
3195

    
3196

    
3197

    
3198

    
3199

    
3200
/* Grammar from proto/ospf/config.Y */
3201

    
3202

    
3203
ospf_variant:
3204
   OSPF    { $$ = 1; }
3205
 | OSPF V2 { $$ = 1; }
3206
 | OSPF V3 { $$ = 0; }
3207
 ;
3208

    
3209
ospf_proto_start: proto_start ospf_variant
3210
{
3211
  this_proto = proto_config_new(&proto_ospf, $1);
3212
  this_proto->net_type = $2 ? NET_IP4 : 0;
3213

    
3214
  init_list(&OSPF_CFG->area_list);
3215
  init_list(&OSPF_CFG->vlink_list);
3216
  OSPF_CFG->ecmp = rt_default_ecmp;
3217
  OSPF_CFG->tick = OSPF_DEFAULT_TICK;
3218
  OSPF_CFG->ospf2 = $2;
3219
  OSPF_CFG->af_ext = !$2;
3220
};
3221

    
3222
ospf_proto:
3223
   ospf_proto_start proto_name '{'
3224
 | ospf_proto ospf_proto_item ';'
3225
 ;
3226

    
3227
ospf_af_mc:
3228
             { $$ = 0; }
3229
 | MULTICAST { $$ = 1; }
3230
 ;
3231

    
3232
/* We redefine proto_channel to add multicast flag */
3233
ospf_channel_start: net_type ospf_af_mc
3234
{
3235
  /* TODO: change name for multicast channels */
3236
  $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
3237

    
3238
  /* Save the multicast flag */
3239
  if (this_channel == proto_cf_main_channel(this_proto))
3240
    OSPF_CFG->af_mc = $2;
3241
};
3242

    
3243
ospf_channel: ospf_channel_start channel_opt_list channel_end;
3244

    
3245
ospf_proto_item:
3246
   proto_item
3247
 | ospf_channel { this_proto->net_type = $1->net_type; }
3248
 | RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
3249
 | RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
3250
 | STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
3251
 | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
3252
 | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
3253
 | MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
3254
 | TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
3255
 | INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
3256
 | ospf_area
3257
 ;
3258

    
3259
ospf_area_start: AREA idval {
3260
  this_area = cfg_allocz(sizeof(struct ospf_area_config));
3261
  add_tail(&OSPF_CFG->area_list, NODE this_area);
3262
  this_area->areaid = $2;
3263
  this_area->default_cost = OSPF_DEFAULT_STUB_COST;
3264
  this_area->type = OPT_E;
3265
  this_area->transint = OSPF_DEFAULT_TRANSINT;
3266

    
3267
  init_list(&this_area->patt_list);
3268
  init_list(&this_area->net_list);
3269
  init_list(&this_area->enet_list);
3270
  init_list(&this_area->stubnet_list);
3271
 }
3272
 ;
3273

    
3274
ospf_area: ospf_area_start '{' ospf_area_opts '}' { ospf_area_finish(); }
3275
 ;
3276

    
3277
ospf_area_opts:
3278
   /* empty */
3279
 | ospf_area_opts ospf_area_item ';'
3280
 ;
3281

    
3282
ospf_area_item:
3283
   STUB bool { this_area->type = $2 ? 0 : OPT_E; /* We should remove the option */ }
3284
 | NSSA { this_area->type = OPT_N; }
3285
 | SUMMARY bool { this_area->summary = $2; }
3286
 | DEFAULT NSSA bool { this_area->default_nssa = $3; }
3287
 | DEFAULT COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
3288
 | DEFAULT COST2 expr { this_area->default_cost = $3 | LSA_EXT3_EBIT; ospf_check_defcost($3); }
3289
 | STUB COST expr { this_area->default_cost = $3; ospf_check_defcost($3); }
3290
 | TRANSLATOR bool { this_area->translator = $2; }
3291
 | TRANSLATOR STABILITY expr { this_area->transint = $3; }
3292
 | NETWORKS { this_nets = &this_area->net_list; } '{' pref_list '}'
3293
 | EXTERNAL { this_nets = &this_area->enet_list; } '{' pref_list '}'
3294
 | STUBNET ospf_stubnet
3295
 | INTERFACE ospf_iface
3296
 | ospf_vlink
3297
 ;
3298

    
3299
ospf_stubnet:
3300
   ospf_stubnet_start '{' ospf_stubnet_opts '}'
3301
 | ospf_stubnet_start
3302
 ;
3303

    
3304
ospf_stubnet_start:
3305
   net_ip {
3306
     this_stubnet = cfg_allocz(sizeof(struct ospf_stubnet_config));
3307
     add_tail(&this_area->stubnet_list, NODE this_stubnet);
3308
     this_stubnet->prefix = $1;
3309
     this_stubnet->cost = COST_D;
3310
   }
3311
 ;
3312

    
3313
ospf_stubnet_opts:
3314
   /* empty */
3315
 | ospf_stubnet_opts ospf_stubnet_item ';'
3316
 ;
3317

    
3318
ospf_stubnet_item:
3319
   HIDDEN bool { this_stubnet->hidden = $2; }
3320
 | SUMMARY bool { this_stubnet->summary = $2; }
3321
 | COST expr { this_stubnet->cost = $2; }
3322
 ;
3323

    
3324
ospf_vlink:
3325
   ospf_vlink_start ospf_instance_id '{' ospf_vlink_opts '}' { ospf_iface_finish(); }
3326
 | ospf_vlink_start ospf_instance_id { ospf_iface_finish(); }
3327
 ;
3328

    
3329
ospf_vlink_opts:
3330
   /* empty */
3331
 | ospf_vlink_opts ospf_vlink_item ';'
3332
 ;
3333

    
3334
ospf_vlink_item:
3335
 | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
3336
 | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
3337
 | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
3338
 | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
3339
 | DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
3340
 | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
3341
 | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE;  }
3342
 | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
3343
 | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
3344
 | password_list { ospf_check_auth(); }
3345
 ;
3346

    
3347
ospf_vlink_start: VIRTUAL LINK idval
3348
 {
3349
  if (this_area->areaid == 0) cf_error("Virtual link cannot be in backbone");
3350
  this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
3351
  add_tail(&OSPF_CFG->vlink_list, NODE this_ipatt);
3352
  init_list(&this_ipatt->ipn_list);
3353
  OSPF_PATT->voa = this_area->areaid;
3354
  OSPF_PATT->vid = $3;
3355
  OSPF_PATT->helloint = HELLOINT_D;
3356
  OSPF_PATT->rxmtint = RXMTINT_D;
3357
  OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
3358
  OSPF_PATT->deadc = DEADC_D;
3359
  OSPF_PATT->type = OSPF_IT_VLINK;
3360
  init_list(&OSPF_PATT->nbma_list);
3361
  reset_passwords();
3362
 }
3363
;
3364

    
3365
ospf_iface_item:
3366
   COST expr { OSPF_PATT->cost = $2 ; if (($2<=0) || ($2>65535)) cf_error("Cost must be in range 1-65535"); }
3367
 | HELLO expr { OSPF_PATT->helloint = $2 ; if (($2<=0) || ($2>65535)) cf_error("Hello interval must be in range 1-65535"); }
3368
 | POLL expr { OSPF_PATT->pollint = $2 ; if ($2<=0) cf_error("Poll int must be greater than zero"); }
3369
 | RETRANSMIT expr { OSPF_PATT->rxmtint = $2 ; if ($2<=1) cf_error("Retransmit int must be greater than one"); }
3370
 | WAIT expr { OSPF_PATT->waitint = $2 ; if ($2<=1) cf_error("Wait interval must be greater than one"); }
3371
 | DEAD expr { OSPF_PATT->deadint = $2 ; if ($2<=1) cf_error("Dead interval must be greater than one"); }
3372
 | DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
3373
 | TYPE BROADCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
3374
 | TYPE BCAST { OSPF_PATT->type = OSPF_IT_BCAST ; }
3375
 | TYPE NONBROADCAST { OSPF_PATT->type = OSPF_IT_NBMA ; }
3376
 | TYPE NBMA { OSPF_PATT->type = OSPF_IT_NBMA ; }
3377
 | TYPE POINTOPOINT { OSPF_PATT->type = OSPF_IT_PTP ; }
3378
 | TYPE PTP { OSPF_PATT->type = OSPF_IT_PTP ; }
3379
 | TYPE POINTOMULTIPOINT { OSPF_PATT->type = OSPF_IT_PTMP ; }
3380
 | TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
3381
 | REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); }
3382
 | PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask option requires OSPFv2"); }
3383
 | TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
3384
 | PRIORITY expr { OSPF_PATT->priority = $2 ; if ($2>255) cf_error("Priority must be in range 0-255"); }
3385
 | STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
3386
 | STUB bool { OSPF_PATT->stub = $2 ; }
3387
 | CHECK LINK bool { OSPF_PATT->check_link = $3; }
3388
 | ECMP WEIGHT expr { OSPF_PATT->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
3389
 | LINK LSA SUPPRESSION bool { OSPF_PATT->link_lsa_suppression = $4; if (!ospf_cfg_is_v3()) cf_error("Link LSA suppression option requires OSPFv3"); }
3390
 | NEIGHBORS '{' nbma_list '}'
3391
 | AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
3392
 | AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
3393
 | AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
3394
 | RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
3395
 | RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
3396
 | RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
3397
 | TX tos { OSPF_PATT->tx_tos = $2; }
3398
 | TX PRIORITY expr { OSPF_PATT->tx_priority = $3; }
3399
 | TX LENGTH expr { OSPF_PATT->tx_length = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("TX length must be in range 256-65535"); }
3400
 | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
3401
 | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
3402
 | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
3403
 | password_list { ospf_check_auth(); }
3404
 ;
3405

    
3406
pref_list:
3407
 /* empty */
3408
 | pref_list pref_item
3409
 ;
3410

    
3411
pref_item: pref_base pref_opt ';' ;
3412

    
3413
pref_base: net_ip
3414
 {
3415
   this_pref = cfg_allocz(sizeof(struct area_net_config));
3416
   add_tail(this_nets, NODE this_pref);
3417
   this_pref->prefix = $1;
3418
 }
3419
;
3420

    
3421
pref_opt:
3422
 /* empty */
3423
 | HIDDEN { this_pref->hidden = 1; }
3424
 | TAG expr { this_pref->tag = $2; }
3425
 ;
3426

    
3427
nbma_list:
3428
 /* empty */
3429
 | nbma_list nbma_item
3430
 ;
3431

    
3432
nbma_eligible:
3433
 /* empty */ { $$ = 0; }
3434
 | ELIGIBLE { $$ = 1; }
3435
 ;
3436

    
3437
nbma_item: ipa nbma_eligible ';'
3438
 {
3439
   this_nbma = cfg_allocz(sizeof(struct nbma_node));
3440
   add_tail(&OSPF_PATT->nbma_list, NODE this_nbma);
3441
   this_nbma->ip=$1;
3442
   this_nbma->eligible=$2;
3443
 }
3444
;
3445

    
3446
ospf_iface_start:
3447
 {
3448
  this_ipatt = cfg_allocz(sizeof(struct ospf_iface_patt));
3449
  add_tail(&this_area->patt_list, NODE this_ipatt);
3450
  init_list(&this_ipatt->ipn_list);
3451
  OSPF_PATT->cost = COST_D;
3452
  OSPF_PATT->helloint = HELLOINT_D;
3453
  OSPF_PATT->pollint = POLLINT_D;
3454
  OSPF_PATT->rxmtint = RXMTINT_D;
3455
  OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
3456
  OSPF_PATT->priority = PRIORITY_D;
3457
  OSPF_PATT->deadc = DEADC_D;
3458
  OSPF_PATT->type = OSPF_IT_UNDEF;
3459
  init_list(&OSPF_PATT->nbma_list);
3460
  OSPF_PATT->check_link = 1;
3461
  OSPF_PATT->ptp_netmask = 2; /* not specified */
3462
  OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
3463
  OSPF_PATT->tx_priority = sk_priority_control;
3464
  reset_passwords();
3465
 }
3466
;
3467

    
3468
ospf_instance_id:
3469
   /* empty */
3470
 | INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
3471
 ;
3472

    
3473
ospf_iface_patt_list:
3474
   iface_patt_list { if (ospf_cfg_is_v3()) iface_patt_check(); } ospf_instance_id
3475
 ;
3476

    
3477
ospf_iface_opts:
3478
   /* empty */
3479
 | ospf_iface_opts ospf_iface_item ';'
3480
 ;
3481

    
3482
ospf_iface_opt_list:
3483
   /* empty */
3484
 | '{' ospf_iface_opts '}'
3485
 ;
3486

    
3487
ospf_iface:
3488
  ospf_iface_start ospf_iface_patt_list ospf_iface_opt_list { ospf_iface_finish(); }
3489
 ;
3490

    
3491

    
3492
;
3493
cmd_SHOW_OSPF: SHOW OSPF optsym END
3494
{ ospf_sh(proto_get_named($3, &proto_ospf)); };
3495

    
3496
cmd_SHOW_OSPF_NEIGHBORS: SHOW OSPF NEIGHBORS optsym opttext END
3497
{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); };
3498

    
3499
cmd_SHOW_OSPF_INTERFACE: SHOW OSPF INTERFACE optsym opttext END
3500
{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
3501

    
3502

    
3503

    
3504
cmd_SHOW_OSPF_TOPOLOGY: SHOW OSPF TOPOLOGY optsym opttext END
3505
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); };
3506

    
3507
cmd_SHOW_OSPF_TOPOLOGY_ALL: SHOW OSPF TOPOLOGY ALL optsym opttext END
3508
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); };
3509

    
3510

    
3511

    
3512
cmd_SHOW_OSPF_STATE: SHOW OSPF STATE optsym opttext END
3513
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); };
3514

    
3515
cmd_SHOW_OSPF_STATE_ALL: SHOW OSPF STATE ALL optsym opttext END
3516
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); };
3517

    
3518
;
3519
cmd_SHOW_OSPF_LSADB: SHOW OSPF LSADB lsadb_args END
3520
{ ospf_sh_lsadb($4); };
3521

    
3522
lsadb_args:
3523
   /* empty */ {
3524
     $$ = cfg_allocz(sizeof(struct lsadb_show_data));
3525
   }
3526
 | lsadb_args GLOBAL { $$ = $1; $$->scope = LSA_SCOPE_AS; }
3527
 | lsadb_args AREA idval { $$ = $1; $$->scope = LSA_SCOPE_AREA; $$->area = $3; }
3528
 | lsadb_args LINK { $$ = $1; $$->scope = 1; /* hack, 0 is no filter */ }
3529
 | lsadb_args TYPE NUM { $$ = $1; $$->type = $3; }
3530
 | lsadb_args LSID idval { $$ = $1; $$->lsid = $3; }
3531
 | lsadb_args SELF { $$ = $1; $$->router = SH_ROUTER_SELF; }
3532
 | lsadb_args ROUTER idval { $$ = $1; $$->router = $3; }
3533
 | lsadb_args SYM { $$ = $1; $$->name = $2; }
3534
 ;
3535

    
3536
/* Grammar from proto/pipe/config.Y */
3537

    
3538

    
3539
pipe_proto_start: proto_start PIPE
3540
{
3541
  this_proto = proto_config_new(&proto_pipe, $1);
3542
  this_channel = channel_config_new(NULL, NULL, 0, this_proto);
3543
  this_channel->in_filter = FILTER_ACCEPT;
3544
  this_channel->out_filter = FILTER_ACCEPT;
3545
};
3546

    
3547
pipe_proto:
3548
   pipe_proto_start proto_name '{'
3549
 | pipe_proto proto_item ';'
3550
 | pipe_proto channel_item ';'
3551
 | pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
3552
 ;
3553

    
3554
/* Grammar from proto/radv/config.Y */
3555

    
3556

    
3557
radv_proto_start: proto_start RADV
3558
{
3559
  this_proto = proto_config_new(&proto_radv, $1);
3560

    
3561
  init_list(&RADV_CFG->patt_list);
3562
  init_list(&RADV_CFG->pref_list);
3563
  init_list(&RADV_CFG->rdnss_list);
3564
  init_list(&RADV_CFG->dnssl_list);
3565
};
3566

    
3567
radv_proto_item:
3568
   proto_item
3569
 | proto_channel
3570
 | INTERFACE radv_iface
3571
 | PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
3572
 | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
3573
 | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
3574
 | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
3575
 | PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
3576
 ;
3577

    
3578
radv_proto_opts:
3579
   /* empty */
3580
 | radv_proto_opts radv_proto_item ';'
3581
 ;
3582

    
3583
radv_proto:
3584
   radv_proto_start proto_name '{' radv_proto_opts '}';
3585

    
3586

    
3587
radv_iface_start:
3588
{
3589
  this_ipatt = cfg_allocz(sizeof(struct radv_iface_config));
3590
  add_tail(&RADV_CFG->patt_list, NODE this_ipatt);
3591
  init_list(&this_ipatt->ipn_list);
3592
  init_list(&RADV_IFACE->pref_list);
3593
  init_list(&RADV_IFACE->rdnss_list);
3594
  init_list(&RADV_IFACE->dnssl_list);
3595

    
3596
  RADV_IFACE->min_ra_int = (u32) -1; /* undefined */
3597
  RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
3598
  RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
3599
  RADV_IFACE->prefix_linger_time = (u32) -1;
3600
  RADV_IFACE->route_linger_time = (u32) -1;
3601
  RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
3602
  RADV_IFACE->default_lifetime = (u32) -1;
3603
  RADV_IFACE->default_lifetime_sensitive = 1;
3604
  RADV_IFACE->default_preference = RA_PREF_MEDIUM;
3605
  RADV_IFACE->route_lifetime = (u32) -1;
3606
  RADV_IFACE->route_lifetime_sensitive = 0;
3607
  RADV_IFACE->route_preference = RA_PREF_MEDIUM;
3608
};
3609

    
3610
radv_iface_item:
3611
   MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); }
3612
 | 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"); }
3613
 | MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
3614
 | MANAGED bool { RADV_IFACE->managed = $2; }
3615
 | OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
3616
 | LINK MTU expr { RADV_IFACE->link_mtu = $3; }
3617
 | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); }
3618
 | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; }
3619
 | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); }
3620
 | DEFAULT LIFETIME expr radv_sensitive {
3621
     RADV_IFACE->default_lifetime = $3;
3622
     if ($3 > 9000)  cf_error("Default lifetime must be in range 0-9000");
3623
     if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4;
3624
   }
3625
 | ROUTE LIFETIME expr radv_sensitive {
3626
     RADV_IFACE->route_lifetime = $3;
3627
     if ($4 != (uint) -1) RADV_IFACE->route_lifetime_sensitive = $4;
3628
   }
3629
 | DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; }
3630
 | ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; }
3631
 | PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; }
3632
 | ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; }
3633
 | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
3634
 | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
3635
 | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
3636
 | RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
3637
 | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
3638
 ;
3639

    
3640
radv_preference:
3641
   LOW { $$ = RA_PREF_LOW; }
3642
 | MEDIUM { $$ = RA_PREF_MEDIUM; }
3643
 | HIGH { $$ = RA_PREF_HIGH; }
3644

    
3645
radv_iface_finish:
3646
{
3647
  struct radv_iface_config *ic = RADV_IFACE;
3648

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

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

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

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

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

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

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

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

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

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

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

    
3683

    
3684
radv_iface_opts:
3685
   /* empty */
3686
 | radv_iface_opts radv_iface_item ';'
3687
 ;
3688

    
3689
radv_iface_opt_list:
3690
   /* empty */
3691
 | '{' radv_iface_opts '}'
3692
 ;
3693

    
3694
radv_iface:
3695
  radv_iface_start iface_patt_list_nopx radv_iface_opt_list radv_iface_finish;
3696

    
3697

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

    
3703
  RADV_PREFIX->onlink = 1;
3704
  RADV_PREFIX->autonomous = 1;
3705
  RADV_PREFIX->valid_lifetime = DEFAULT_VALID_LIFETIME;
3706
  RADV_PREFIX->preferred_lifetime = DEFAULT_PREFERRED_LIFETIME;
3707
};
3708

    
3709
radv_prefix_item:
3710
   SKIP bool { RADV_PREFIX->skip = $2; }
3711
 | ONLINK bool { RADV_PREFIX->onlink = $2; }
3712
 | AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; }
3713
 | VALID LIFETIME expr radv_sensitive {
3714
     RADV_PREFIX->valid_lifetime = $3;
3715
     if ($4 != (uint) -1) RADV_PREFIX->valid_lifetime_sensitive = $4;
3716
   }
3717
 | PREFERRED LIFETIME expr radv_sensitive {
3718
     RADV_PREFIX->preferred_lifetime = $3;
3719
     if ($4 != (uint) -1) RADV_PREFIX->preferred_lifetime_sensitive = $4;
3720
   }
3721
 ;
3722

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

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

    
3732
radv_prefix_opts:
3733
   /* empty */
3734
 | radv_prefix_opts radv_prefix_item ';'
3735
 ;
3736

    
3737
radv_prefix_opt_list:
3738
   /* empty */
3739
 | '{' radv_prefix_opts '}'
3740
 ;
3741

    
3742
radv_prefix:
3743
  radv_prefix_start radv_prefix_opt_list radv_prefix_finish;
3744

    
3745

    
3746

    
3747
radv_rdnss_node: ipa
3748
{
3749
  struct radv_rdnss_config *cf = cfg_allocz(sizeof(struct radv_rdnss_config));
3750
  add_tail(&radv_dns_list, NODE cf);
3751

    
3752
  cf->server = $1;
3753
  cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
3754
};
3755

    
3756
radv_rdnss_start:
3757
{
3758
  RADV_RDNSS->lifetime = 0;
3759
  RADV_RDNSS->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
3760
};
3761

    
3762
radv_rdnss_item:
3763
 | NS radv_rdnss_node
3764
 | LIFETIME radv_mult { RADV_RDNSS->lifetime = $2; RADV_RDNSS->lifetime_mult = radv_mult_val; }
3765
 ;
3766

    
3767
radv_rdnss_finish:
3768
{
3769
  if (EMPTY_LIST(radv_dns_list))
3770
    cf_error("No nameserver in RDNSS section");
3771

    
3772
  struct radv_rdnss_config *cf;
3773
  WALK_LIST(cf, radv_dns_list)
3774
  {
3775
    cf->lifetime = RADV_RDNSS->lifetime;
3776
    cf->lifetime_mult = RADV_RDNSS->lifetime_mult;
3777
  }
3778
};
3779

    
3780
radv_rdnss_opts:
3781
   /* empty */
3782
 | radv_rdnss_opts radv_rdnss_item ';'
3783
 ;
3784

    
3785
radv_rdnss:
3786
   radv_rdnss_node
3787
 | '{' radv_rdnss_start radv_rdnss_opts '}' radv_rdnss_finish
3788
 ;
3789

    
3790

    
3791
radv_dnssl_node: TEXT
3792
{
3793
  struct radv_dnssl_config *cf = cfg_allocz(sizeof(struct radv_dnssl_config));
3794
  add_tail(&radv_dns_list, NODE cf);
3795

    
3796
  cf->domain = $1;
3797
  cf->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
3798

    
3799
  if (radv_process_domain(cf) < 0)
3800
    cf_error("Invalid domain dame");
3801
};
3802

    
3803
radv_dnssl_start:
3804
{
3805
  RADV_DNSSL->lifetime = 0;
3806
  RADV_DNSSL->lifetime_mult = DEFAULT_DNS_LIFETIME_MULT;
3807
};
3808

    
3809
radv_dnssl_item:
3810
 | DOMAIN radv_dnssl_node
3811
 | LIFETIME radv_mult { RADV_DNSSL->lifetime = $2; RADV_DNSSL->lifetime_mult = radv_mult_val; }
3812
 ;
3813

    
3814
radv_dnssl_finish:
3815
{
3816
  if (EMPTY_LIST(radv_dns_list))
3817
    cf_error("No domain in DNSSL section");
3818

    
3819
  struct radv_dnssl_config *cf;
3820
  WALK_LIST(cf, radv_dns_list)
3821
  {
3822
    cf->lifetime = RADV_DNSSL->lifetime;
3823
    cf->lifetime_mult = RADV_DNSSL->lifetime_mult;
3824
  }
3825
};
3826

    
3827
radv_dnssl_opts:
3828
   /* empty */
3829
 | radv_dnssl_opts radv_dnssl_item ';'
3830
 ;
3831

    
3832
radv_dnssl:
3833
   radv_dnssl_node
3834
 | '{' radv_dnssl_start radv_dnssl_opts '}' radv_dnssl_finish
3835
 ;
3836

    
3837

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

    
3843
radv_sensitive:
3844
   /* empty */ { $$ = (uint) -1; }
3845
 | SENSITIVE bool { $$ = $2; }
3846
 ;
3847

    
3848

    
3849
/* Grammar from proto/rip/config.Y */
3850

    
3851

    
3852
rip_variant:
3853
   RIP    { $$ = 1; }
3854
 | RIP NG { $$ = 0; }
3855
 ;
3856

    
3857
rip_proto_start: proto_start rip_variant
3858
{
3859
  this_proto = proto_config_new(&proto_rip, $1);
3860
  this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
3861

    
3862
  init_list(&RIP_CFG->patt_list);
3863
  RIP_CFG->rip2 = $2;
3864
  RIP_CFG->ecmp = rt_default_ecmp;
3865
  RIP_CFG->infinity = RIP_DEFAULT_INFINITY;
3866
  RIP_CFG->min_timeout_time = 60 S_;
3867
  RIP_CFG->max_garbage_time = 60 S_;
3868
};
3869

    
3870
rip_proto_item:
3871
   proto_item
3872
 | proto_channel
3873
 | ECMP bool		{ RIP_CFG->ecmp = $2 ? RIP_DEFAULT_ECMP_LIMIT : 0; }
3874
 | ECMP bool LIMIT expr	{ RIP_CFG->ecmp = $2 ? $4 : 0; }
3875
 | INFINITY expr	{ RIP_CFG->infinity = $2; }
3876
 | INTERFACE rip_iface
3877
 ;
3878

    
3879
rip_proto_opts:
3880
   /* empty */
3881
 | rip_proto_opts rip_proto_item ';'
3882
 ;
3883

    
3884
rip_proto:
3885
   rip_proto_start proto_name '{' rip_proto_opts '}';
3886

    
3887

    
3888
rip_iface_start:
3889
{
3890
  this_ipatt = cfg_allocz(sizeof(struct rip_iface_config));
3891
  add_tail(&RIP_CFG->patt_list, NODE this_ipatt);
3892
  init_list(&this_ipatt->ipn_list);
3893
  reset_passwords();
3894

    
3895
  RIP_IFACE->metric = 1;
3896
  RIP_IFACE->port = rip_cfg_is_v2() ? RIP_PORT : RIP_NG_PORT;
3897
  RIP_IFACE->version = rip_cfg_is_v2() ? RIP_V2 : RIP_V1;
3898
  RIP_IFACE->split_horizon = 1;
3899
  RIP_IFACE->poison_reverse = 1;
3900
  RIP_IFACE->check_zero = 1;
3901
  RIP_IFACE->check_link = 1;
3902
  RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1;
3903
  RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
3904
  RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
3905
  RIP_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
3906
  RIP_IFACE->tx_priority = sk_priority_control;
3907
  RIP_IFACE->update_time = RIP_DEFAULT_UPDATE_TIME;
3908
  RIP_IFACE->timeout_time = RIP_DEFAULT_TIMEOUT_TIME;
3909
  RIP_IFACE->garbage_time = RIP_DEFAULT_GARBAGE_TIME;
3910
};
3911

    
3912
rip_iface_finish:
3913
{
3914
  /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */
3915
  if (!RIP_IFACE->mode)
3916
    RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ?
3917
      RIP_IM_BROADCAST : RIP_IM_MULTICAST;
3918

    
3919
  RIP_IFACE->passwords = get_passwords();
3920

    
3921
  if (!RIP_IFACE->auth_type != !RIP_IFACE->passwords)
3922
    log(L_WARN "Authentication and password options should be used together");
3923

    
3924
  if (RIP_IFACE->passwords)
3925
  {
3926
    struct password_item *pass;
3927
    WALK_LIST(pass, *RIP_IFACE->passwords)
3928
    {
3929
      if (pass->alg && (RIP_IFACE->auth_type != RIP_AUTH_CRYPTO))
3930
	cf_error("Password algorithm option requires cryptographic authentication");
3931

    
3932
      /* Set default crypto algorithm (MD5) */
3933
      if (!pass->alg && (RIP_IFACE->auth_type == RIP_AUTH_CRYPTO))
3934
	pass->alg = ALG_MD5;
3935
    }
3936
  }
3937

    
3938
  RIP_CFG->min_timeout_time = MIN_(RIP_CFG->min_timeout_time, RIP_IFACE->timeout_time);
3939
  RIP_CFG->max_garbage_time = MAX_(RIP_CFG->max_garbage_time, RIP_IFACE->garbage_time);
3940
};
3941

    
3942
rip_iface_item:
3943
   METRIC expr		{ RIP_IFACE->metric = $2; if (($2<1) || ($2>255)) cf_error("Metric must be in range 1-255"); }
3944
 | MODE MULTICAST	{ RIP_IFACE->mode = RIP_IM_MULTICAST; }
3945
 | MODE BROADCAST	{ RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng()) cf_error("Broadcast not supported in RIPng"); }
3946
 | PASSIVE bool		{ RIP_IFACE->passive = $2; }
3947
 | ADDRESS ipa		{ RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2()) cf_error("IP address version mismatch"); }
3948
 | PORT expr		{ RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
3949
 | VERSION expr		{ RIP_IFACE->version = $2;
3950
			  if (rip_cfg_is_ng()) cf_error("Version not supported in RIPng");
3951
			  if (($2 != RIP_V1) && ($2 != RIP_V2)) cf_error("Unsupported version");
3952
			}
3953
 | VERSION ONLY bool	{ RIP_IFACE->version_only = $3; }
3954
 | SPLIT HORIZON bool	{ RIP_IFACE->split_horizon = $3; }
3955
 | POISON REVERSE bool	{ RIP_IFACE->poison_reverse = $3; }
3956
 | CHECK ZERO bool	{ RIP_IFACE->check_zero = $3; }
3957
 | UPDATE TIME expr	{ RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
3958
 | TIMEOUT TIME expr	{ RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
3959
 | GARBAGE TIME expr	{ RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
3960
 | ECMP WEIGHT expr	{ RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
3961
 | RX BUFFER expr	{ RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
3962
 | TX LENGTH expr	{ RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
3963
 | TX tos		{ RIP_IFACE->tx_tos = $2; }
3964
 | TX PRIORITY expr	{ RIP_IFACE->tx_priority = $3; }
3965
 | TTL SECURITY bool	{ RIP_IFACE->ttl_security = $3; }
3966
 | TTL SECURITY TX ONLY	{ RIP_IFACE->ttl_security = 2; }
3967
 | CHECK LINK bool	{ RIP_IFACE->check_link = $3; }
3968
 | BFD bool		{ RIP_IFACE->bfd = $2; cf_check_bfd($2); }
3969
 | AUTHENTICATION rip_auth { RIP_IFACE->auth_type = $2; if ($2) rip_check_auth(); }
3970
 | password_list	{ rip_check_auth(); }
3971
;
3972

    
3973
rip_auth:
3974
   NONE			{ $$ = RIP_AUTH_NONE; }
3975
 | PLAINTEXT		{ $$ = RIP_AUTH_PLAIN; }
3976
 | CRYPTOGRAPHIC	{ $$ = RIP_AUTH_CRYPTO; }
3977
 | MD5			{ $$ = RIP_AUTH_CRYPTO; }	/* For backward compatibility */
3978
 ;
3979

    
3980
rip_iface_opts:
3981
   /* empty */
3982
 | rip_iface_opts rip_iface_item ';'
3983
 ;
3984

    
3985
rip_iface_opt_list:
3986
   /* empty */
3987
 | '{' rip_iface_opts '}'
3988
 ;
3989

    
3990
rip_iface:
3991
  rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish;
3992

    
3993

    
3994

    
3995
;
3996

    
3997
cmd_SHOW_RIP_INTERFACES: SHOW RIP INTERFACES optsym opttext END
3998
{ rip_show_interfaces(proto_get_named($4, &proto_rip), $5); };
3999

    
4000
cmd_SHOW_RIP_NEIGHBORS: SHOW RIP NEIGHBORS optsym opttext END
4001
{ rip_show_neighbors(proto_get_named($4, &proto_rip), $5); };
4002

    
4003

    
4004
/* Grammar from proto/static/config.Y */
4005

    
4006

    
4007
static_proto_start: proto_start STATIC
4008
{
4009
  this_proto = proto_config_new(&proto_static, $1);
4010
  init_list(&STATIC_CFG->routes);
4011
};
4012

    
4013
static_proto:
4014
   static_proto_start proto_name '{'
4015
 | static_proto proto_item ';'
4016
 | static_proto proto_channel ';' { this_proto->net_type = $2->net_type; }
4017
 | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
4018
 | static_proto IGP TABLE rtable ';' {
4019
    if ($4->addr_type == NET_IP4)
4020
      STATIC_CFG->igp_table_ip4 = $4;
4021
    else if ($4->addr_type == NET_IP6)
4022
      STATIC_CFG->igp_table_ip6 = $4;
4023
    else
4024
      cf_error("Incompatible IGP table type");
4025
   }
4026
 | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
4027
 ;
4028

    
4029
stat_nexthop:
4030
    VIA ipa ipa_scope {
4031
      this_snh = static_nexthop_new();
4032
      this_snh->via = $2;
4033
      this_snh->iface = $3;
4034
    }
4035
  | VIA TEXT {
4036
      this_snh = static_nexthop_new();
4037
      this_snh->via = IPA_NONE;
4038
      this_snh->iface = if_get_by_name($2);
4039
    }
4040
  | stat_nexthop MPLS label_stack {
4041
    this_snh->mls = $3;
4042
  }
4043
  | stat_nexthop ONLINK bool {
4044
    this_snh->onlink = $3;
4045
  }
4046
  | stat_nexthop WEIGHT expr {
4047
    this_snh->weight = $3 - 1;
4048
    if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
4049
  }
4050
  | stat_nexthop BFD bool {
4051
    this_snh->use_bfd = $3; cf_check_bfd($3);
4052
  }
4053
;
4054

    
4055
stat_nexthops:
4056
    stat_nexthop
4057
  | stat_nexthops stat_nexthop
4058
;
4059

    
4060
stat_route0: ROUTE net_any {
4061
     this_srt = cfg_allocz(sizeof(struct static_route));
4062
     add_tail(&STATIC_CFG->routes, &this_srt->n);
4063
     this_srt->net = $2;
4064
     this_srt_last_cmd = &(this_srt->cmds);
4065
     this_srt->mp_next = NULL;
4066
     this_snh = NULL;
4067
  }
4068
 ;
4069

    
4070
stat_route:
4071
   stat_route0 stat_nexthops
4072
 | stat_route0 RECURSIVE ipa {
4073
      this_srt->dest = RTDX_RECURSIVE;
4074
      this_srt->via = $3;
4075
   }
4076
 | stat_route0 RECURSIVE ipa MPLS label_stack {
4077
      this_srt->dest = RTDX_RECURSIVE;
4078
      this_srt->via = $3;
4079
      this_srt->mls = $5;
4080
   }
4081
 | stat_route0			{ this_srt->dest = RTD_NONE; }
4082
 | stat_route0 DROP		{ this_srt->dest = RTD_BLACKHOLE; }
4083
 | stat_route0 REJECT		{ this_srt->dest = RTD_UNREACHABLE; }
4084
 | stat_route0 BLACKHOLE	{ this_srt->dest = RTD_BLACKHOLE; }
4085
 | stat_route0 UNREACHABLE	{ this_srt->dest = RTD_UNREACHABLE; }
4086
 | stat_route0 PROHIBIT		{ this_srt->dest = RTD_PROHIBIT; }
4087
 ;
4088

    
4089
stat_route_item:
4090
   cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
4091
 ;
4092

    
4093
stat_route_opts:
4094
   /* empty */
4095
 | stat_route_opts stat_route_item
4096
 ;
4097

    
4098
stat_route_opt_list:
4099
   /* empty */
4100
 | '{' stat_route_opts '}'
4101
 ;
4102

    
4103

    
4104
cmd_SHOW_STATIC: SHOW STATIC optsym END
4105
{ static_show(proto_get_named($3, &proto_static)); } ;
4106

    
4107
/* Grammar from sysdep/linux/netlink.Y */
4108

    
4109

    
4110
kern_sys_item:
4111
   KERNEL TABLE expr { THIS_KRT->sys.table_id = $3; }
4112
 | METRIC expr { THIS_KRT->sys.metric = $2; }
4113
 ;
4114

    
4115

    
4116

    
4117

    
4118

    
4119

    
4120
/* Grammar from sysdep/unix/config.Y */
4121

    
4122

    
4123
log_config: LOG log_file log_mask ';' {
4124
    struct log_config *c = cfg_allocz(sizeof(struct log_config));
4125
    c->fh = $2;
4126
    c->mask = $3;
4127
    add_tail(&new_config->logfiles, &c->n);
4128
  }
4129
 ;
4130

    
4131
syslog_name:
4132
   NAME text { $$ = $2; }
4133
 | { $$ = bird_name; }
4134
 ;
4135

    
4136
log_file:
4137
   text {
4138
     FILE *f = tracked_fopen(new_config->pool, $1, "a");
4139
     if (!f) cf_error("Unable to open log file `%s': %m", $1);
4140
     $$ = f;
4141
   }
4142
 | SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
4143
 | STDERR { $$ = stderr; }
4144
 ;
4145

    
4146
log_mask:
4147
   ALL { $$ = ~0; }
4148
 | '{' log_mask_list '}' { $$ = $2; }
4149
 ;
4150

    
4151
log_mask_list:
4152
   log_cat { $$ = 1 << $1; }
4153
 | log_mask_list ',' log_cat { $$ = $1 | (1 << $3); }
4154
 ;
4155

    
4156
log_cat:
4157
   DEBUG { $$ = L_DEBUG[0]; }
4158
 | TRACE { $$ = L_TRACE[0]; }
4159
 | INFO { $$ = L_INFO[0]; }
4160
 | REMOTE { $$ = L_REMOTE[0]; }
4161
 | WARNING { $$ = L_WARN[0]; }
4162
 | ERROR { $$ = L_ERR[0]; }
4163
 | AUTH { $$ = L_AUTH[0]; }
4164
 | FATAL { $$ = L_FATAL[0]; }
4165
 | BUG { $$ = L_BUG[0]; }
4166
 ;
4167

    
4168

    
4169

    
4170
mrtdump_base:
4171
   MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
4172
 | MRTDUMP text ';' {
4173
     FILE *f = tracked_fopen(new_config->pool, $2, "a");
4174
     if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
4175
     new_config->mrtdump_file = fileno(f);
4176
   }
4177
 ;
4178

    
4179

    
4180

    
4181
debug_unix:
4182
   DEBUG LATENCY bool { new_config->latency_debug = $3; }
4183
 | DEBUG LATENCY LIMIT expr_us { new_config->latency_limit = $4; }
4184
 | WATCHDOG WARNING expr_us { new_config->watchdog_warning = $3; }
4185
 | WATCHDOG TIMEOUT expr_us { new_config->watchdog_timeout = ($3 + 999999) TO_S; }
4186
 ;
4187

    
4188

    
4189
/* Unix specific commands */
4190

    
4191

    
4192

    
4193
cmd_CONFIGURE: CONFIGURE cfg_name cfg_timeout END
4194
{ cmd_reconfig($2, RECONFIG_HARD, $3); } ;
4195

    
4196
cmd_CONFIGURE_SOFT: CONFIGURE SOFT cfg_name cfg_timeout END
4197
{ cmd_reconfig($3, RECONFIG_SOFT, $4); } ;
4198

    
4199
/* Hack to get input completion for 'timeout' */
4200

    
4201

    
4202

    
4203
cmd_CONFIGURE_CONFIRM: CONFIGURE CONFIRM  END
4204
{ cmd_reconfig_confirm(); } ;
4205

    
4206
cmd_CONFIGURE_UNDO: CONFIGURE UNDO  END
4207
{ cmd_reconfig_undo(); } ;
4208

    
4209
cmd_CONFIGURE_CHECK: CONFIGURE CHECK cfg_name END
4210
{ cmd_check_config($3); } ;
4211

    
4212
cmd_DOWN: DOWN  END
4213
{ cmd_shutdown(); } ;
4214

    
4215
cfg_name:
4216
   /* empty */ { $$ = NULL; }
4217
 | TEXT
4218
 ;
4219

    
4220
cfg_timeout:
4221
   /* empty */ { $$ = 0; }
4222
 | TIMEOUT { $$ = UNIX_DEFAULT_CONFIGURE_TIMEOUT; }
4223
 | TIMEOUT expr { $$ = $2; }
4224
 ;
4225

    
4226
/* Grammar from sysdep/unix/krt.Y */
4227

    
4228
/* Kernel syncer protocol */
4229

    
4230

    
4231
kern_proto_start: proto_start KERNEL {
4232
     this_proto = krt_init_config($1);
4233
}
4234
 ;
4235

    
4236

    
4237
kern_mp_limit:
4238
   /* empty */ { $$ = KRT_DEFAULT_ECMP_LIMIT; }
4239
 | LIMIT expr  { $$ = $2; if (($2 <= 0) || ($2 > 255)) cf_error("Merge paths limit must be in range 1-255"); }
4240
 ;
4241

    
4242
kern_item:
4243
   proto_item
4244
 | proto_channel { this_proto->net_type = $1->net_type; }
4245
 | PERSIST bool { THIS_KRT->persist = $2; }
4246
 | SCAN TIME expr {
4247
      /* Scan time of 0 means scan on startup only */
4248
      THIS_KRT->scan_time = $3 S_;
4249
   }
4250
 | LEARN bool {
4251
      THIS_KRT->learn = $2;
4252
#ifndef KRT_ALLOW_LEARN
4253
      if ($2)
4254
	cf_error("Learning of kernel routes not supported on this platform");
4255
#endif
4256
   }
4257
 | DEVICE ROUTES bool { THIS_KRT->devroutes = $3; }
4258
 | GRACEFUL RESTART bool { THIS_KRT->graceful_restart = $3; }
4259
 | MERGE PATHS bool kern_mp_limit {
4260
      krt_set_merge_paths(this_channel, $3, $4);
4261
#ifndef KRT_ALLOW_MERGE_PATHS
4262
      if ($3)
4263
	cf_error("Path merging not supported on this platform");
4264
#endif
4265
   }
4266
 ;
4267

    
4268
/* Kernel interface protocol */
4269

    
4270

    
4271
kif_proto_start: proto_start DEVICE { this_proto = kif_init_config($1); }
4272
 ;
4273

    
4274

    
4275
kif_item:
4276
   proto_item
4277
 | INTERFACE kif_iface
4278
 | SCAN TIME expr {
4279
      /* Scan time of 0 means scan on startup only */
4280
      THIS_KIF->scan_time = $3 S_;
4281
   }
4282
 ;
4283

    
4284
kif_iface_start:
4285
{
4286
  this_ipatt = cfg_allocz(sizeof(struct kif_iface_config));
4287
  add_tail(&THIS_KIF->iface_list, NODE this_ipatt);
4288
  init_list(&this_ipatt->ipn_list);
4289
}
4290

    
4291
kif_iface_item:
4292
   PREFERRED ipa { kif_set_preferred($2); }
4293
 ;
4294

    
4295
kif_iface_opts:
4296
   /* empty */
4297
 | kif_iface_opts kif_iface_item ';'
4298
 ;
4299

    
4300
kif_iface_opt_list:
4301
   /* empty */
4302
 | '{' kif_iface_opts '}'
4303
 ;
4304

    
4305
kif_iface:
4306
  kif_iface_start iface_patt_list_nopx kif_iface_opt_list;
4307

    
4308

    
4309

    
4310

    
4311
/* Dynamic rules */
4312

    
4313

    
4314
conf: ';' | definition | filter_def | filter_eval | bt_test_suite | function_def | rtrid | gr_opts | table | proto { proto_postconfig(); } | debug_default | timeformat_base | log_config | mrtdump_base | debug_unix ;
4315
dynamic_attr: INVALID_TOKEN { $$ = NULL; } | IGP_METRIC
4316
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } | BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_BABEL_METRIC); } | BGP_ORIGIN
4317
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_BGP_ORIGIN, EA_CODE(EAP_BGP, BA_ORIGIN)); } | BGP_PATH
4318
	{ $$ = f_new_dynamic_attr(EAF_TYPE_AS_PATH, T_PATH, EA_CODE(EAP_BGP, BA_AS_PATH)); } | BGP_NEXT_HOP
4319
	{ $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_CODE(EAP_BGP, BA_NEXT_HOP)); } | BGP_MED
4320
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); } | BGP_LOCAL_PREF
4321
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); } | BGP_ATOMIC_AGGR
4322
	{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(EAP_BGP, BA_ATOMIC_AGGR)); } | BGP_AGGREGATOR
4323
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(EAP_BGP, BA_AGGREGATOR)); } | BGP_COMMUNITY
4324
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_COMMUNITY)); } | BGP_ORIGINATOR_ID
4325
	{ $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUAD, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID)); } | BGP_CLUSTER_LIST
4326
	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); } | BGP_EXT_COMMUNITY
4327
	{ $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(EAP_BGP, BA_EXT_COMMUNITY)); } | BGP_LARGE_COMMUNITY
4328
	{ $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(EAP_BGP, BA_LARGE_COMMUNITY)); } | OSPF_METRIC1 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_METRIC1); } | OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_METRIC2); } | OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_TAG); } | OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID | EAF_TEMP, T_QUAD, EA_OSPF_ROUTER_ID); } | RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); } | RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); } | RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_RIP_METRIC); } | RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_RIP_TAG); } | KRT_PREFSRC	{ $$ = f_new_dynamic_attr(EAF_TYPE_IP_ADDRESS, T_IP, EA_KRT_PREFSRC); } | KRT_REALM	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REALM); } | KRT_SCOPE	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SCOPE); } | KRT_MTU		{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_MTU); } | KRT_WINDOW	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_WINDOW); } | KRT_RTT		{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTT); } | KRT_RTTVAR	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTTVAR); } | KRT_SSTRESH	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_SSTRESH); } | KRT_CWND		{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_CWND); } | KRT_ADVMSS	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_ADVMSS); } | KRT_REORDERING	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_REORDERING); } | KRT_HOPLIMIT	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_HOPLIMIT); } | KRT_INITCWND	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITCWND); } | KRT_RTO_MIN	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_RTO_MIN); } | KRT_INITRWND	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_INITRWND); } | KRT_QUICKACK	{ $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_KRT_QUICKACK); } | KRT_LOCK_MTU	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_MTU); } | KRT_LOCK_WINDOW	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_WINDOW); } | KRT_LOCK_RTT	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTT); } | KRT_LOCK_RTTVAR	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTTVAR); } | KRT_LOCK_SSTRESH	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_SSTHRESH); } | KRT_LOCK_CWND	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_CWND); } | KRT_LOCK_ADVMSS	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_ADVMSS); } | KRT_LOCK_REORDERING { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_REORDERING); } | KRT_LOCK_HOPLIMIT { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_HOPLIMIT); } | KRT_LOCK_RTO_MIN { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_LOCK_RTO_MIN); } | KRT_FEATURE_ECN	{ $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ECN); } | KRT_FEATURE_ALLFRAG { $$ = f_new_dynamic_attr(EAF_TYPE_BITFIELD, T_BOOL, EA_KRT_FEATURE_ALLFRAG); } | KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_KRT_SOURCE); } | KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_KRT_METRIC); } ;
4329
proto: dev_proto '}' | bfd_proto | babel_proto | bgp_proto '}'  | ospf_proto '}' { ospf_proto_finish(); }  | pipe_proto '}' { this_channel = NULL; }  | radv_proto | rip_proto | static_proto '}' | kern_proto '}' | kif_proto '}' ;
4330
cli_cmd: cmd_SHOW_STATUS | cmd_SHOW_MEMORY | cmd_SHOW_PROTOCOLS | cmd_SHOW_PROTOCOLS_ALL | cmd_SHOW_INTERFACES | cmd_SHOW_INTERFACES_SUMMARY | cmd_SHOW_ROUTE | cmd_SHOW_SYMBOLS | cmd_DUMP_RESOURCES | cmd_DUMP_SOCKETS | cmd_DUMP_EVENTS | cmd_DUMP_INTERFACES | cmd_DUMP_NEIGHBORS | cmd_DUMP_ATTRIBUTES | cmd_DUMP_ROUTES | cmd_DUMP_PROTOCOLS | cmd_EVAL | cmd_ECHO | cmd_DISABLE | cmd_ENABLE | cmd_RESTART | cmd_RELOAD | cmd_RELOAD_IN | cmd_RELOAD_OUT | cmd_DEBUG | cmd_MRTDUMP | cmd_RESTRICT | cmd_SHOW_BFD_SESSIONS | cmd_SHOW_BABEL_INTERFACES | cmd_SHOW_BABEL_NEIGHBORS | cmd_SHOW_BABEL_ENTRIES | cmd_SHOW_BABEL_ROUTES | cmd_SHOW_OSPF | cmd_SHOW_OSPF_NEIGHBORS | cmd_SHOW_OSPF_INTERFACE | cmd_SHOW_OSPF_TOPOLOGY | cmd_SHOW_OSPF_TOPOLOGY_ALL | cmd_SHOW_OSPF_STATE | cmd_SHOW_OSPF_STATE_ALL | cmd_SHOW_OSPF_LSADB | cmd_SHOW_RIP_INTERFACES | cmd_SHOW_RIP_NEIGHBORS | cmd_SHOW_STATIC | cmd_CONFIGURE | cmd_CONFIGURE_SOFT | cmd_CONFIGURE_CONFIRM | cmd_CONFIGURE_UNDO | cmd_CONFIGURE_CHECK | cmd_DOWN ;
4331
kern_proto: kern_proto kern_sys_item ';' | kern_proto_start proto_name '{' | kern_proto kern_item ';' ;
4332
kif_proto: kif_proto_start proto_name '{' | kif_proto kif_item ';' ;
4333

    
4334
%%
4335
/* C Code from conf/confbase.Y */
4336

    
4337
/* C Code from conf/flowspec.Y */
4338

    
4339
/* C Code from nest/config.Y */
4340

    
4341
/* C Code from proto/bfd/config.Y */
4342

    
4343
/* C Code from proto/babel/config.Y */
4344

    
4345
/* C Code from proto/bgp/config.Y */
4346

    
4347
/* C Code from proto/ospf/config.Y */
4348

    
4349
/* C Code from proto/pipe/config.Y */
4350

    
4351
/* C Code from proto/radv/config.Y */
4352

    
4353
/* C Code from proto/rip/config.Y */
4354

    
4355
/* C Code from proto/static/config.Y */
4356

    
4357
/* C Code from sysdep/linux/netlink.Y */
4358

    
4359
/* C Code from sysdep/unix/config.Y */
4360

    
4361
/* C Code from sysdep/unix/krt.Y */
4362