1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
/*
* 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, VRF)
%type <i> mpls_label_policy
%type <cc> mpls_channel_start mpls_channel
%type <msrc> show_mpls_ranges_args
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; }
| VRF { $$ = MPLS_POLICY_VRF; }
;
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;
show_mpls_ranges_args:
/* empty */
{
if (EMPTY_LIST(config->mpls_domains))
cf_error("No MPLS domain defined");
$$ = cfg_allocz(sizeof(struct mpls_show_ranges_cmd));
}
| show_mpls_ranges_args symbol_known
{
if ($2->class == SYM_MPLS_DOMAIN)
{
if ($$->domain)
cf_error("Only one MPLS domain expected");
$$->domain = $2->mpls_domain;
}
else if ($2->class == SYM_MPLS_RANGE)
{
if ($$->range)
cf_error("Only one MPLS label range expected");
if ($$->domain != $2->mpls_range->domain)
cf_error("MPLS label range from different MPLS domain");
$$->domain = $2->mpls_range->domain;
$$->range = $2->mpls_range;
}
else
cf_error("MPLS domain or label range expected");
}
| show_mpls_ranges_args STATIC
{
if ($$->range)
cf_error("Only one MPLS label range expected");
$$->domain = $$->domain ?: cf_default_mpls_domain(config);
$$->range = $$->domain->static_range;
}
| show_mpls_ranges_args DYNAMIC
{
if ($$->range)
cf_error("Only one MPLS label range expected");
$$->domain = $$->domain ?: cf_default_mpls_domain(config);
$$->range = $$->domain->dynamic_range;
}
;
CF_CLI(SHOW MPLS RANGES, show_mpls_ranges_args, [<MPLS domain> | <MPLS range>], [[Show MPLS ranges]])
{ mpls_show_ranges($4); } ;
CF_CODE
CF_END
|