diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2022-09-15 01:38:18 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2023-10-04 13:01:21 +0200 |
commit | 333ddd4f981b90d5d3dff166b6abf9bf40bede9f (patch) | |
tree | cfe873631d254b9198d7040a7f922f65d158f15d /nest/mpls.Y | |
parent | e55696a4f88b63c622bb3a0360f9114d01253e53 (diff) |
MPLS subsystem
The MPLS subsystem manages MPLS labels and handles their allocation to
MPLS-aware routing protocols. These labels are then attached to IP or VPN
routes representing label switched paths -- LSPs.
There was already a preliminary MPLS support consisting of MPLS label
net_addr, MPLS routing tables with static MPLS routes, remote labels in
next hops, and kernel protocol support.
This patch adds the MPLS domain as a basic structure representing local
label space with dynamic label allocator and configurable label ranges.
To represent LSPs, allocated local labels can be attached as route
attributes to IP or VPN routes with local labels as attributes.
There are several steps for handling LSP routes in routing protocols --
deciding to which forwarding equivalence class (FEC) the LSP route
belongs, allocating labels for new FECs, announcing MPLS routes for new
FECs, attaching labels to LSP routes. The FEC map structure implements
basic code for managing FECs in routing protocols, therefore existing
protocols can be made MPLS-aware by adding FEC map and delegating
most work related to local label management to it.
Diffstat (limited to 'nest/mpls.Y')
-rw-r--r-- | nest/mpls.Y | 141 |
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 |