config.Y 22.7 KB
Newer Older
1 2 3
/*
 *	BIRD -- Core Configuration
 *
4
 *	(c) 1998--2000 Martin Mares <mj@ucw.cz>
5
 *      (c) 2004       Ondrej Filip <feela@network.cz>
6 7 8 9 10 11
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

CF_HDR

12
#include "nest/rt-dev.h"
13
#include "nest/password.h"
14
#include "nest/cmds.h"
15
#include "lib/lists.h"
16
#include "lib/mac.h"
17

18 19 20
CF_DEFINES

static struct proto_config *this_proto;
21
static struct channel_config *this_channel;
22
static struct iface_patt *this_ipatt;
23
static struct iface_patt_node *this_ipn;
Jan Moskyto Matejka's avatar
Jan Moskyto Matejka committed
24
/* static struct roa_table_config *this_roa_table; */
25 26
static list *this_p_list;
static struct password_item *this_p_item;
27 28
static int password_id;

29 30 31 32 33 34
static void
iface_patt_check(void)
{
  struct iface_patt_node *pn;

  WALK_LIST(pn, this_ipatt->ipn_list)
35
    if (!pn->pattern || pn->prefix.type)
36 37 38 39
      cf_error("Interface name/mask expected, not IP prefix");
}


40 41 42
static inline void
reset_passwords(void)
{
43
  this_p_list = NULL;
44 45 46
}

static inline list *
47 48 49 50 51 52 53
get_passwords(void)
{
  list *rv = this_p_list;
  this_p_list = NULL;
  return rv;
}

54 55 56 57 58 59 60 61 62
static void
proto_postconfig(void)
{
  CALL(this_proto->protocol->postconfig, this_proto);
  this_channel = NULL;
  this_proto = NULL;
}


63
#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
64

65 66
CF_DECLS

67
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
68
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
69
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
70
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
71
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
72
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
73
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
Jan Maria Matejka's avatar
Jan Maria Matejka committed
74
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
75
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
76
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
77
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
78

79
/* For r_args_channel */
80
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
81

82
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
83
	RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
84
CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
85
CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
86
CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
87

88
%type <i32> idval
89
%type <f> imexport
90
%type <r> rtable
91
%type <s> optsym
92
%type <ra> r_args
93
%type <sd> sym_args
94
%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
95
%type <ps> proto_patt proto_patt2
96 97
%type <cc> channel_start proto_channel
%type <cl> limit_spec
98 99
%type <net> r_args_for_val
%type <net_ptr> r_args_for
100
%type <t> r_args_channel
101 102 103

CF_GRAMMAR

104 105
/* Setting of router ID */

106
conf: rtrid ;
107

108
rtrid:
109 110
   ROUTER ID idval ';' { new_config->router_id = $3; }
 | ROUTER ID FROM iface_patt ';' { new_config->router_id_from = this_ipatt; }
111 112 113
 ;

idval:
114
   NUM { $$ = $1; }
115
 | '(' term ')' { $$ = f_eval_int($2); }
116
 | IP4 { $$ = ip4_to_u32($1); }
117 118 119
 | SYM {
     if ($1->class == (SYM_CONSTANT | T_INT) || $1->class == (SYM_CONSTANT | T_QUAD))
       $$ = SYM_VAL($1).i;
120 121
     else if (($1->class == (SYM_CONSTANT | T_IP)) && ipa_is_ip4(SYM_VAL($1).ip))
       $$ = ipa_to_u32(SYM_VAL($1).ip);
122
     else
123
       cf_error("Number or IPv4 address constant expected");
124
   }
125 126
 ;

127
conf: gr_opts ;
128 129 130 131

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


132
/* Network types (for tables, channels) */
133

134 135
net_type:
   IPV4 { $$ = NET_IP4; }
136
 | IPV6 { $$ = NET_IP6; }
137
 | IPV6 SADR { $$ = NET_IP6_SADR; }
138 139
 | VPN4 { $$ = NET_VPN4; }
 | VPN6 { $$ = NET_VPN6; }
140 141
 | ROA4 { $$ = NET_ROA4; }
 | ROA6 { $$ = NET_ROA6; }
142 143
 | FLOW4{ $$ = NET_FLOW4; }
 | FLOW6{ $$ = NET_FLOW6; }
144
 | MPLS { $$ = NET_MPLS; }
145 146
 ;

147
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR)
148

149 150 151

/* Creation of routing tables */

152
conf: table ;
153

154
table_sorted:
155
	  { $$ = 0; }
156 157 158
 | SORTED { $$ = 1; }
 ;

159
table: net_type TABLE SYM table_sorted {
160
   struct rtable_config *cf;
161 162
   cf = rt_new_table($3, $1);
   cf->sorted = $4;
163 164 165
   }
 ;

166

167 168
/* Definition of protocols */

169
conf: proto { proto_postconfig(); } ;
170

171 172 173
proto_start:
   PROTOCOL { $$ = SYM_PROTO; }
 | TEMPLATE { $$ = SYM_TEMPLATE; }
174
 ;
175 176 177

proto_name:
   /* EMPTY */ {
178
     struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
179
     s->class = this_proto->class;
180 181 182 183
     s->def = this_proto;
     this_proto->name = s->name;
     }
 | SYM {
184
     cf_define_symbol($1, this_proto->class, this_proto);
185 186
     this_proto->name = $1->name;
   }
187 188
 | FROM SYM {
     struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
189 190
     s->class = this_proto->class;
     s->def = this_proto;
191
     this_proto->name = s->name;
192

193 194 195
     if (($2->class != SYM_TEMPLATE) && ($2->class != SYM_PROTO)) cf_error("Template or protocol name expected");
     proto_copy_config(this_proto, $2->def);
   }
196 197 198 199
 | SYM FROM SYM {
     cf_define_symbol($1, this_proto->class, this_proto);
     this_proto->name = $1->name;

200
     if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
201 202
     proto_copy_config(this_proto, $3->def);
   }
203 204 205 206
 ;

proto_item:
   /* EMPTY */
207
 | DISABLED bool { this_proto->disabled = $2; }
208
 | DEBUG debug_mask { this_proto->debug = $2; }
209
 | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
210
 | ROUTER ID idval { this_proto->router_id = $3; }
211
 | DESCRIPTION text { this_proto->dsc = $2; }
212
 | VRF text { this_proto->vrf = if_get_by_name($2); }
213 214
 ;

215 216 217

channel_start: net_type
{
218
  $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
};

channel_item:
   TABLE rtable {
     if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
       cf_error("Incompatible table type");
     this_channel->table = $2;
   }
 | IMPORT imexport { this_channel->in_filter = $2; }
 | EXPORT imexport { this_channel->out_filter = $2; }
 | RECEIVE LIMIT limit_spec { this_channel->rx_limit = $3; }
 | IMPORT LIMIT limit_spec { this_channel->in_limit = $3; }
 | EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
 | PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
 | IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
 ;

channel_opts:
   /* empty */
 | channel_opts channel_item ';'
 ;

channel_opt_list:
   /* empty */
 | '{' channel_opts '}'
 ;

channel_end:
{
  if (!this_channel->table)
    cf_error("Routing table not specified");

  this_channel = NULL;
};

proto_channel: channel_start channel_opt_list channel_end;


rtable:
   SYM {
     if ($1->class != SYM_TABLE) cf_error("Table expected");
     $$ = $1->def;
   }
 ;

264 265
imexport:
   FILTER filter { $$ = $2; }
266
 | where_filter
267 268
 | ALL { $$ = FILTER_ACCEPT; }
 | NONE { $$ = FILTER_REJECT; }
269 270
 ;

271
limit_action:
272
   /* default */ { $$ = PLA_DISABLE; }
273 274 275 276
 | ACTION WARN { $$ = PLA_WARN; }
 | ACTION BLOCK { $$ = PLA_BLOCK; }
 | ACTION RESTART { $$ = PLA_RESTART; }
 | ACTION DISABLE { $$ = PLA_DISABLE; }
277 278 279
 ;

limit_spec:
280 281
   expr limit_action { $$ = (struct channel_limit){ .limit = $1, $$.action = $2 }; }
 | OFF { $$ = (struct channel_limit){}; }
282 283
 ;

284

285
conf: debug_default ;
286 287 288

debug_default:
   DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
289
 | DEBUG COMMANDS expr { new_config->cli_debug = $3; }
290 291
 ;

292 293
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */

294
conf: timeformat_base ;
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

timeformat_which:
   ROUTE { $$ = &new_config->tf_route; }
 | PROTOCOL { $$ = &new_config->tf_proto; }
 | BASE { $$ = &new_config->tf_base; }
 | LOG { $$ = &new_config->tf_log; }
 ;

timeformat_spec:
   timeformat_which TEXT { *$1 = (struct timeformat){$2, NULL, 0}; }
 | timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, (s64) $3 S_}; }
 | timeformat_which ISO SHORT    { *$1 = TM_ISO_SHORT_S; }
 | timeformat_which ISO SHORT MS { *$1 = TM_ISO_SHORT_MS; }
 | timeformat_which ISO SHORT US { *$1 = TM_ISO_SHORT_US; }
 | timeformat_which ISO LONG    { *$1 = TM_ISO_LONG_S; }
 | timeformat_which ISO LONG MS { *$1 = TM_ISO_LONG_MS; }
 | timeformat_which ISO LONG US { *$1 = TM_ISO_LONG_US; }
 ;

timeformat_base:
   TIMEFORMAT timeformat_spec ';'
 ;


319 320
/* Interface patterns */

321 322 323 324 325 326 327 328 329
iface_patt_node_init:
   /* EMPTY */ {
     struct iface_patt_node *ipn = cfg_allocz(sizeof(struct iface_patt_node));
     add_tail(&this_ipatt->ipn_list, NODE ipn);
     this_ipn = ipn;
   }
 ;

iface_patt_node_body:
330 331
   TEXT { this_ipn->pattern = $1; /* this_ipn->prefix stays zero */ }
 | opttext net_or_ipa { this_ipn->pattern = $1; this_ipn->prefix = $2; }
332 333 334 335 336 337 338 339
 ;

iface_negate:
       { this_ipn->positive = 1; }
 | '-' { this_ipn->positive = 0; }
 ;

iface_patt_node:
340
   iface_patt_node_init iface_negate iface_patt_node_body
341 342 343 344 345 346
 ;


iface_patt_list:
   iface_patt_node
 | iface_patt_list ',' iface_patt_node
347 348
 ;

349 350 351
/* For name/mask-only iface patterns */
iface_patt_list_nopx: iface_patt_list { iface_patt_check(); }

352 353 354 355 356 357 358 359 360 361 362
iface_patt_init: {
   /* Generic this_ipatt init */
   this_ipatt = cfg_allocz(sizeof(struct iface_patt));
   init_list(&this_ipatt->ipn_list);
 }
 ;

iface_patt:
   iface_patt_init iface_patt_list
 ;

363
tos:
364 365
   CLASS expr { $$ = $2 & 0xfc;        if ($2 > 255) cf_error("TX class must be in range 0-255"); }
 | DSCP expr  { $$ = ($2 & 0x3f) << 2; if ($2 > 63)  cf_error("TX DSCP must be in range 0-63"); }
366
 ;
367

368
/* Direct device route protocol */
369

370
proto: dev_proto '}' ;
371

372
dev_proto_start: proto_start DIRECT {
373
     this_proto = proto_config_new(&proto_device, $1);
374
     init_list(&DIRECT_CFG->iface_list);
375 376 377 378
   }
 ;

dev_proto:
379
   dev_proto_start proto_name '{'
380
 | dev_proto proto_item ';'
381
 | dev_proto proto_channel ';'
382
 | dev_proto dev_iface_patt ';'
383
 | dev_proto CHECK LINK bool ';' { DIRECT_CFG->check_link = $4; }
384 385
 ;

386
dev_iface_init:
387
   /* EMPTY */ {
388
     this_ipatt = cfg_allocz(sizeof(struct iface_patt));
389
     add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt);
390
     init_list(&this_ipatt->ipn_list);
391 392 393
   }
 ;

394 395
dev_iface_patt:
   INTERFACE dev_iface_init iface_patt_list
396 397
 ;

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
/* Debug flags */

debug_mask:
   ALL { $$ = ~0; }
 | OFF { $$ = 0; }
 | '{' debug_list '}' { $$ = $2; }
 ;

debug_list:
   debug_flag
 | debug_list ',' debug_flag { $$ = $1 | $3; }
 ;

debug_flag:
   STATES	{ $$ = D_STATES; }
 | ROUTES	{ $$ = D_ROUTES; }
 | FILTERS	{ $$ = D_FILTERS; }
415
 | INTERFACES	{ $$ = D_IFACES; }
416 417 418 419
 | EVENTS	{ $$ = D_EVENTS; }
 | PACKETS	{ $$ = D_PACKETS; }
 ;

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
/* MRTDump flags */

mrtdump_mask:
   ALL { $$ = ~0; }
 | OFF { $$ = 0; }
 | '{' mrtdump_list '}' { $$ = $2; }
 ;

mrtdump_list:
   mrtdump_flag
 | mrtdump_list ',' mrtdump_flag { $$ = $1 | $3; }
 ;

mrtdump_flag:
   STATES	{ $$ = MD_STATES; }
 | MESSAGES	{ $$ = MD_MESSAGES; }
 ;

438 439
/* Password lists */

440 441 442 443 444
password_list:
   PASSWORDS '{' password_items '}'
 | password_item
;

445
password_items:
446 447 448 449 450 451 452 453 454 455
    /* empty */
  | password_item ';' password_items
;

password_item:
    password_item_begin '{' password_item_params '}'
  | password_item_begin
;

password_item_begin:
456
   PASSWORD text {
457
     if (!this_p_list) {
458 459 460
	this_p_list = cfg_alloc(sizeof(list));
	init_list(this_p_list);
	password_id = 1;
461
     }
462 463
     this_p_item = cfg_alloc(sizeof (struct password_item));
     this_p_item->password = $2;
464
     this_p_item->length = strlen($2);
465 466 467 468
     this_p_item->genfrom = 0;
     this_p_item->gento = TIME_INFINITY;
     this_p_item->accfrom = 0;
     this_p_item->accto = TIME_INFINITY;
469
     this_p_item->id = password_id++;
470
     this_p_item->alg = ALG_UNDEFINED;
471
     add_tail(this_p_list, &this_p_item->n);
472
   }
473
;
474

475
password_item_params:
476
   /* empty */ { }
477 478 479 480 481 482
 | GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
 | GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
 | ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
 | ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
 | FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
 | TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
483
 | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
484
 | ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
485 486
 ;

487 488 489 490 491 492 493 494 495 496 497 498
password_algorithm:
   KEYED MD5	{ $$ = ALG_MD5; }
 | KEYED SHA1	{ $$ = ALG_SHA1; }
 | KEYED SHA256	{ $$ = ALG_SHA256; }
 | KEYED SHA384	{ $$ = ALG_SHA384; }
 | KEYED SHA512	{ $$ = ALG_SHA512; }
 | HMAC MD5	{ $$ = ALG_HMAC_MD5; }
 | HMAC SHA1	{ $$ = ALG_HMAC_SHA1; }
 | HMAC SHA256	{ $$ = ALG_HMAC_SHA256; }
 | HMAC SHA384	{ $$ = ALG_HMAC_SHA384; }
 | HMAC SHA512	{ $$ = ALG_HMAC_SHA512; }
 ;
499

500
/* Core commands */
501
CF_CLI_HELP(SHOW, ..., [[Show status information]])
502

503
CF_CLI(SHOW STATUS,,, [[Show router status]])
504
{ cmd_show_status(); } ;
505

506 507 508
CF_CLI(SHOW MEMORY,,, [[Show memory usage]])
{ cmd_show_memory(); } ;

509
CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]])
510
{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
511

512
CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
513
{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
514

515 516 517 518 519
optsym:
   SYM
 | /* empty */ { $$ = NULL; }
 ;

520 521 522 523 524 525
CF_CLI(SHOW INTERFACES,,, [[Show network interfaces]])
{ if_show(); } ;

CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]])
{ if_show_summary(); } ;

526
CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]])
527
CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filter <f>|where <cond>] [all] [primary] [filtered] [(export|preexport|noexport) <p>] [protocol <p>] [stats|count]]], [[Show routing table]])
528 529 530 531 532
{ rt_show($3); } ;

r_args:
   /* empty */ {
     $$ = cfg_allocz(sizeof(struct rt_show_data));
533
     init_list(&($$->tables));
534
     $$->filter = FILTER_ACCEPT;
Maria Matejka's avatar
Maria Matejka committed
535
     $$->running_on_config = new_config->fallback;
536
   }
537
 | r_args net_any {
538
     $$ = $1;
539 540
     if ($$->addr) cf_error("Only one prefix expected");
     $$->addr = $2;
541
   }
542
 | r_args FOR r_args_for {
543
     $$ = $1;
544
     if ($$->addr) cf_error("Only one prefix expected");
545
     $$->show_for = 1;
546
     $$->addr = $3;
547
   }
548 549 550
 | r_args TABLE SYM {
     $$ = $1;
     if ($3->class != SYM_TABLE) cf_error("%s is not a table", $3->name);
551 552 553 554 555 556 557 558 559
     rt_show_add_table($$, ((struct rtable_config *)$3->def)->table);
     $$->tables_defined_by = RSD_TDB_DIRECT;
   }
 | r_args TABLE ALL {
     struct rtable_config *t;
     $$ = $1;
     WALK_LIST(t, config->tables)
       rt_show_add_table($$, t->table);
     $$->tables_defined_by = RSD_TDB_ALL;
560
   }
561 562 563 564 565 566 567 568 569 570
 | r_args IMPORT TABLE SYM '.' r_args_channel {
     $$ = $1;
     struct proto_config *cf = (void *) $4->def;
     if ($4->class != SYM_PROTO || !cf->proto) cf_error("%s is not a protocol", $4->name);
     struct channel *c = proto_find_channel_by_name(cf->proto, $6);
     if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
     if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6);
     rt_show_add_table($$, c->in_table);
     $$->tables_defined_by = RSD_TDB_DIRECT;
   }
571 572
 | r_args FILTER filter {
     $$ = $1;
573
     if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
574 575
     $$->filter = $3;
   }
576 577 578 579 580
 | r_args where_filter {
     $$ = $1;
     if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
     $$->filter = $2;
   }
581 582 583 584
 | r_args ALL {
     $$ = $1;
     $$->verbose = 1;
   }
585 586 587 588
 | r_args PRIMARY {
     $$ = $1;
     $$->primary_only = 1;
   }
589
 | r_args FILTERED {
590
     $$ = $1;
591
     $$->filtered = 1;
592
   }
593
 | r_args export_mode SYM {
594 595
     struct proto_config *c = (struct proto_config *) $3->def;
     $$ = $1;
596
     if ($$->export_mode) cf_error("Export specified twice");
597
     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
598 599
     $$->export_mode = $2;
     $$->export_protocol = c->proto;
600
     $$->tables_defined_by = RSD_TDB_INDIRECT;
601
   }
602 603 604 605 606 607 608 609 610 611
 | r_args export_mode SYM '.' r_args_channel {
     struct proto_config *c = (struct proto_config *) $3->def;
     $$ = $1;
     if ($$->export_mode) cf_error("Export specified twice");
     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
     $$->export_mode = $2;
     $$->export_channel = proto_find_channel_by_name(c->proto, $5);
     if (!$$->export_channel) cf_error("Export channel not found");
     $$->tables_defined_by = RSD_TDB_INDIRECT;
   }
612 613 614 615 616 617
 | r_args PROTOCOL SYM {
     struct proto_config *c = (struct proto_config *) $3->def;
     $$ = $1;
     if ($$->show_protocol) cf_error("Protocol specified twice");
     if ($3->class != SYM_PROTO || !c->proto) cf_error("%s is not a protocol", $3->name);
     $$->show_protocol = c->proto;
618
     $$->tables_defined_by = RSD_TDB_INDIRECT;
619
   }
620 621 622 623
 | r_args STATS {
     $$ = $1;
     $$->stats = 1;
   }
624 625 626 627
 | r_args COUNT {
     $$ = $1;
     $$->stats = 2;
   }
628 629
 ;

630 631 632 633 634 635 636
r_args_for:
  r_args_for_val {
    $$ = cfg_alloc($1.length);
    net_copy($$, &$1);
  }
 | net_vpn4_
 | net_vpn6_
637
 | net_ip6_sadr_
638 639 640 641 642 643 644 645
 | VPN_RD IP4 {
    $$ = cfg_alloc(sizeof(net_addr_vpn4));
    net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1);
  }
 | VPN_RD IP6 {
    $$ = cfg_alloc(sizeof(net_addr_vpn6));
    net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1);
  }
646 647 648 649
 | IP6 FROM IP6 {
    $$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
    net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
  }
650 651 652 653 654 655 656
 | SYM {
     if ($1->class == (SYM_CONSTANT | T_IP))
     {
       $$ = cfg_alloc(ipa_is_ip4(SYM_VAL($1).ip) ? sizeof(net_addr_ip4) : sizeof(net_addr_ip6));
       net_fill_ip_host($$, SYM_VAL($1).ip);
     }
     else if (($1->class == (SYM_CONSTANT | T_NET)) && net_type_match(SYM_VAL($1).net, NB_IP | NB_VPN))
Ondřej Zajíček's avatar
Ondřej Zajíček committed
657
       $$ = (net_addr *) SYM_VAL($1).net; /* Avoid const warning */
658 659 660 661 662 663 664 665 666 667 668
     else
       cf_error("IP address or network expected");
   }
 ;

r_args_for_val:
   net_ip4_
 | net_ip6_
 | IP4 { net_fill_ip4(&($$), $1, IP4_MAX_PREFIX_LENGTH); }
 | IP6 { net_fill_ip6(&($$), $1, IP6_MAX_PREFIX_LENGTH); }

669 670 671 672
export_mode:
   PREEXPORT	{ $$ = RSEM_PREEXPORT; }
 | EXPORT	{ $$ = RSEM_EXPORT; }
 | NOEXPORT	{ $$ = RSEM_NOEXPORT; }
673 674
 ;

675 676 677 678 679 680 681 682
/* This is ugly hack */
r_args_channel:
   IPV4		{ $$ = "ipv4"; }
 | IPV4_MC	{ $$ = "ipv4-mc"; }
 | IPV4_MPLS	{ $$ = "ipv4-mpls"; }
 | IPV6		{ $$ = "ipv6"; }
 | IPV6_MC	{ $$ = "ipv6-mc"; }
 | IPV6_MPLS	{ $$ = "ipv6-mpls"; }
683
 | IPV6_SADR	{ $$ = "ipv6-sadr"; }
684 685 686 687 688 689 690 691 692 693 694 695 696 697
 | VPN4		{ $$ = "vpn4"; }
 | VPN4_MC	{ $$ = "vpn4-mc"; }
 | VPN4_MPLS	{ $$ = "vpn4-mpls"; }
 | VPN6		{ $$ = "vpn6"; }
 | VPN6_MC	{ $$ = "vpn6-mc"; }
 | VPN6_MPLS	{ $$ = "vpn6-mpls"; }
 | ROA4		{ $$ = "roa4"; }
 | ROA6		{ $$ = "roa6"; }
 | FLOW4	{ $$ = "flow4"; }
 | FLOW6	{ $$ = "flow6"; }
 | MPLS		{ $$ = "mpls"; }
 | PRI		{ $$ = "pri"; }
 | SEC		{ $$ = "sec"; }
 ;
698

699
CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
700
CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
701 702
{ cmd_show_symbols($3); } ;

703 704 705 706 707 708 709 710 711 712 713 714
sym_args:
   /* empty */ {
     $$ = cfg_allocz(sizeof(struct sym_show_data));
   }
 | sym_args TABLE { $$ = $1; $$->type = SYM_TABLE; }
 | sym_args FUNCTION { $$ = $1; $$->type = SYM_FUNCTION; }
 | sym_args FILTER { $$ = $1; $$->type = SYM_FILTER; }
 | sym_args PROTOCOL { $$ = $1; $$->type = SYM_PROTO; }
 | sym_args TEMPLATE { $$ = $1; $$->type = SYM_TEMPLATE; }
 | sym_args SYM { $$ = $1; $$->sym = $2; }
 ;

715

716 717
CF_CLI_HELP(DUMP, ..., [[Dump debugging information]])
CF_CLI(DUMP RESOURCES,,, [[Dump all allocated resource]])
718
{ rdump(&root_pool); cli_msg(0, ""); } ;
719
CF_CLI(DUMP SOCKETS,,, [[Dump open sockets]])
720
{ sk_dump_all(); cli_msg(0, ""); } ;
721 722
CF_CLI(DUMP EVENTS,,, [[Dump event log]])
{ io_log_dump(); cli_msg(0, ""); } ;
723
CF_CLI(DUMP INTERFACES,,, [[Dump interface information]])
724
{ if_dump_all(); cli_msg(0, ""); } ;
725
CF_CLI(DUMP NEIGHBORS,,, [[Dump neighbor cache]])
726
{ neigh_dump_all(); cli_msg(0, ""); } ;
727
CF_CLI(DUMP ATTRIBUTES,,, [[Dump attribute cache]])
728
{ rta_dump_all(); cli_msg(0, ""); } ;
729
CF_CLI(DUMP ROUTES,,, [[Dump routing table]])
730
{ rt_dump_all(); cli_msg(0, ""); } ;
731
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
732 733
{ protos_dump_all(); cli_msg(0, ""); } ;

734 735 736 737
CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
{ cmd_eval($2); } ;

CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
738
CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug|trace|info|remote|warning|error|auth [, ...] }) [<buffer-size>], [[Control echoing of log messages]]) {
739 740 741 742 743 744 745
  cli_set_log_echo(this_cli, $2, $3);
  cli_msg(0, "");
} ;

echo_mask:
   ALL { $$ = ~0; }
 | OFF { $$ = 0; }
746
 | '{' log_mask_list '}' { $$ = $2; }
747 748 749 750 751 752 753 754 755
 ;

echo_size:
   /* empty */ { $$ = 4096; }
 | NUM {
     if ($1 < 256 || $1 > 65536) cf_error("Invalid log buffer size");
     $$ = $1;
   }
 ;
756

757
CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]])
758
{ proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
759
CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]])
760
{ proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
761
CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]])
762
{ proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
763
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
764
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
765
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
766
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
767
CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
768
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
769

770
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
771
CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
772
{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
773 774

CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
775
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | \"<pattern>\" | all) (all | off | { states|messages [, ...] }), [[Control protocol debugging via MRTdump format]])
776 777 778 779
{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;

CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
{ this_cli->restricted = 1; cli_msg(16, "Access restricted"); } ;
780

781
proto_patt:
782 783 784
   SYM  { $$.ptr = $1; $$.patt = 0; }
 | ALL  { $$.ptr = NULL; $$.patt = 1; }
 | TEXT { $$.ptr = $1; $$.patt = 1; }
785 786
 ;

787 788 789 790 791 792
proto_patt2:
   SYM  { $$.ptr = $1; $$.patt = 0; }
 |      { $$.ptr = NULL; $$.patt = 1; }
 | TEXT { $$.ptr = $1; $$.patt = 1; }
 ;

793
dynamic_attr: IGP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_GEN_IGP_METRIC); } ;
794

795

796 797 798
CF_CODE

CF_END