summaryrefslogtreecommitdiff
path: root/nest/mpls.Y
diff options
context:
space:
mode:
Diffstat (limited to 'nest/mpls.Y')
-rw-r--r--nest/mpls.Y141
1 files changed, 141 insertions, 0 deletions
diff --git a/nest/mpls.Y b/nest/mpls.Y
new file mode 100644
index 00000000..b4ae990b
--- /dev/null
+++ b/nest/mpls.Y
@@ -0,0 +1,141 @@
+/*
+ * BIRD Internet Routing Daemon -- MPLS Structures
+ *
+ * (c) 2022 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2022 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+CF_HDR
+
+#include "nest/mpls.h"
+
+CF_DEFINES
+
+static struct mpls_domain_config *this_mpls_domain;
+static struct mpls_range_config *this_mpls_range;
+
+#define MPLS_CC ((struct mpls_channel_config *) this_channel)
+
+CF_DECLS
+
+CF_KEYWORDS(MPLS, DOMAIN, LABEL, RANGE, STATIC, DYNAMIC, START, LENGTH, POLICY, PREFIX, AGGREGATE)
+
+%type <i> mpls_label_policy
+%type <cc> mpls_channel_start mpls_channel
+
+CF_GRAMMAR
+
+conf: mpls_domain;
+
+mpls_domain: mpls_domain_start mpls_domain_opt_list mpls_domain_end;
+
+mpls_domain_start: MPLS DOMAIN symbol { this_mpls_domain = mpls_domain_config_new($3); };
+
+mpls_domain_opt:
+ mpls_range
+ ;
+
+mpls_domain_opts:
+ /* empty */
+ | mpls_domain_opts mpls_domain_opt ';'
+ ;
+
+mpls_domain_opt_list:
+ /* empty */
+ | '{' mpls_domain_opts '}'
+ ;
+
+mpls_domain_end: { mpls_domain_postconfig(this_mpls_domain); this_mpls_domain = NULL; };
+
+
+mpls_range: mpls_range_start mpls_range_opt_list mpls_range_end;
+
+mpls_range_start: LABEL RANGE symbol
+{
+ if (($3->class == SYM_KEYWORD) && ($3->keyword->value == STATIC))
+ this_mpls_range = this_mpls_domain->static_range;
+ else if (($3->class == SYM_KEYWORD) && ($3->keyword->value == DYNAMIC))
+ this_mpls_range = this_mpls_domain->dynamic_range;
+ else
+ this_mpls_range = mpls_range_config_new(this_mpls_domain, $3);
+};
+
+mpls_range_opt:
+ START expr { this_mpls_range->start = $2; if ($2 >= MPLS_MAX_LABEL) cf_error("MPLS label range start must be less than 2^20"); }
+ | LENGTH expr { this_mpls_range->length = $2; if ($2 >= MPLS_MAX_LABEL) cf_error("MPLS label range length must be less than 2^20"); if (!$2) cf_error("MPLS label range length must be nonzero"); }
+ ;
+
+mpls_range_opts:
+ /* empty */
+ | mpls_range_opts mpls_range_opt ';'
+ ;
+
+mpls_range_opt_list:
+ /* empty */
+ | '{' mpls_range_opts '}'
+ ;
+
+mpls_range_end:
+{
+ struct mpls_range_config *r = this_mpls_range;
+
+ if ((r->start == (uint) -1) || (r->length == (uint) -1))
+ cf_error("MPLS label range start and length must be specified");
+
+ if (r->start + r->length > MPLS_MAX_LABEL)
+ cf_error("MPLS label range end must be less than 2^20");
+
+ this_mpls_range = NULL;
+};
+
+
+mpls_channel: mpls_channel_start mpls_channel_opt_list mpls_channel_end;
+
+mpls_channel_start: MPLS
+{
+ $$ = this_channel = channel_config_get(&channel_mpls, net_label[NET_MPLS], NET_MPLS, this_proto);
+
+ if (EMPTY_LIST(new_config->mpls_domains))
+ cf_error("No MPLS domain defined");
+
+ /* Default values for new channel */
+ if (!MPLS_CC->domain)
+ {
+ MPLS_CC->domain = cf_default_mpls_domain(new_config);
+ MPLS_CC->label_policy = MPLS_POLICY_PREFIX;
+ }
+};
+
+mpls_label_policy:
+ STATIC { $$ = MPLS_POLICY_STATIC; }
+ | PREFIX { $$ = MPLS_POLICY_PREFIX; }
+ | AGGREGATE { $$ = MPLS_POLICY_AGGREGATE; }
+ ;
+
+mpls_channel_opt:
+ channel_item
+ | DOMAIN symbol_known { cf_assert_symbol($2, SYM_MPLS_DOMAIN); MPLS_CC->domain = $2->mpls_domain; }
+ | LABEL RANGE symbol_known { cf_assert_symbol($3, SYM_MPLS_RANGE); MPLS_CC->range = $3->mpls_range; }
+ | LABEL RANGE STATIC { MPLS_CC->range = MPLS_CC->domain->static_range; }
+ | LABEL RANGE DYNAMIC { MPLS_CC->range = MPLS_CC->domain->dynamic_range; }
+ | LABEL POLICY mpls_label_policy { MPLS_CC->label_policy = $3; }
+ ;
+
+mpls_channel_opts:
+ /* empty */
+ | mpls_channel_opts mpls_channel_opt ';'
+ ;
+
+mpls_channel_opt_list:
+ /* empty */
+ | '{' mpls_channel_opts '}'
+ ;
+
+mpls_channel_end: { mpls_channel_postconfig(this_channel); } channel_end;
+
+
+CF_CODE
+
+CF_END