]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_config.c
Merge pull request #8459 from taspelund/no_rmac_on_mac_only
[mirror_frr.git] / pathd / path_pcep_config.c
1 /*
2 * Copyright (C) 2020 NetDEF, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <zebra.h>
20
21 #include <northbound.h>
22 #include <yang.h>
23 #include <printfrr.h>
24 #include "pceplib/pcep_msg_objects.h"
25 #include "pathd/pathd.h"
26 #include "pathd/path_pcep.h"
27 #include "pathd/path_pcep_config.h"
28 #include "pathd/path_pcep_debug.h"
29 #include "thread.h"
30
31 #define MAX_XPATH 256
32 #define MAX_FLOAT_LEN 22
33 #define INETADDR4_MAXLEN 16
34 #define INETADDR6_MAXLEN 40
35
36
37 static void copy_candidate_objfun_info(struct srte_candidate *candidate,
38 struct path *path);
39 static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
40 struct path *path);
41 static struct path_hop *
42 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
43 static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
44 static char *candidate_name(struct srte_candidate *candidate);
45 static enum pcep_lsp_operational_status
46 status_int_to_ext(enum srte_policy_status status);
47 static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
48 static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
49
50 void path_pcep_refine_path(struct path *path)
51 {
52 struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
53 struct srte_lsp *lsp;
54
55 if (candidate == NULL)
56 return;
57
58 lsp = candidate->lsp;
59
60 if (path->name == NULL)
61 path->name = candidate_name(candidate);
62 if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
63 path->type = candidate->type;
64 if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
65 path->create_origin = candidate->protocol_origin;
66 if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
67 && (lsp->segment_list != NULL))
68 path->update_origin = lsp->segment_list->protocol_origin;
69 }
70
71 struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
72 {
73 struct srte_candidate *candidate = lookup_candidate(key);
74 if (candidate == NULL)
75 return NULL;
76 return candidate_to_path(candidate);
77 }
78
79 void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
80 {
81 struct path *path;
82 struct srte_policy *policy;
83 struct srte_candidate *candidate;
84
85 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
86 RB_FOREACH (candidate, srte_candidate_head,
87 &policy->candidate_paths) {
88 path = candidate_to_path(candidate);
89 if (!cb(path, arg))
90 return;
91 }
92 }
93 }
94
95 struct path *candidate_to_path(struct srte_candidate *candidate)
96 {
97 char *name;
98 struct path *path;
99 struct path_hop *hop = NULL;
100 struct path_metric *metric = NULL;
101 struct srte_policy *policy;
102 struct srte_lsp *lsp;
103 enum pcep_lsp_operational_status status;
104 enum srte_protocol_origin update_origin = 0;
105 char *originator = NULL;
106
107 policy = candidate->policy;
108 lsp = candidate->lsp;
109
110 if (lsp->segment_list != NULL) {
111 hop = path_pcep_config_list_path_hops(lsp->segment_list);
112 update_origin = lsp->segment_list->protocol_origin;
113 originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
114 }
115 path = pcep_new_path();
116 name = candidate_name(candidate);
117 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
118 status = status_int_to_ext(policy->status);
119 } else {
120 status = PCEP_LSP_OPERATIONAL_DOWN;
121 }
122 for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
123 struct path_metric *path_metric;
124 struct srte_metric *srte_metric = &lsp->metrics[i];
125 if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
126 path_metric = pcep_new_metric();
127 path_metric->next = metric;
128 metric = path_metric;
129 metric->type = i + 1;
130 metric->value = srte_metric->value;
131 metric->enforce = CHECK_FLAG(srte_metric->flags,
132 F_METRIC_IS_REQUIRED);
133 metric->is_bound = CHECK_FLAG(srte_metric->flags,
134 F_METRIC_IS_BOUND);
135 metric->is_computed = CHECK_FLAG(srte_metric->flags,
136 F_METRIC_IS_COMPUTED);
137 }
138 }
139 *path = (struct path){
140 .nbkey = (struct lsp_nb_key){.color = policy->color,
141 .endpoint = policy->endpoint,
142 .preference =
143 candidate->preference},
144 .create_origin = lsp->protocol_origin,
145 .update_origin = update_origin,
146 .originator = originator,
147 .plsp_id = 0,
148 .name = name,
149 .type = candidate->type,
150 .srp_id = 0,
151 .req_id = 0,
152 .binding_sid = policy->binding_sid,
153 .status = status,
154 .do_remove = false,
155 .go_active = false,
156 .was_created = false,
157 .was_removed = false,
158 .is_synching = false,
159 .is_delegated = false,
160 .first_hop = hop,
161 .first_metric = metric};
162
163 path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
164 if (path->has_bandwidth) {
165 path->enforce_bandwidth =
166 CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
167 path->bandwidth = lsp->bandwidth;
168 } else {
169 path->enforce_bandwidth = true;
170 path->bandwidth = 0;
171 }
172
173 copy_candidate_objfun_info(candidate, path);
174 copy_candidate_affinity_filters(candidate, path);
175
176 return path;
177 }
178
179 void copy_candidate_objfun_info(struct srte_candidate *candidate,
180 struct path *path)
181 {
182 struct srte_lsp *lsp = candidate->lsp;
183
184 if (lsp != NULL) {
185 if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
186 path->has_pce_objfun = true;
187 path->pce_objfun = lsp->objfun;
188 } else {
189 path->has_pce_objfun = false;
190 path->pce_objfun = OBJFUN_UNDEFINED;
191 }
192 }
193 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
194 path->has_pcc_objfun = true;
195 path->pcc_objfun = candidate->objfun;
196 path->enforce_pcc_objfun = CHECK_FLAG(
197 candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
198
199 } else {
200 path->has_pcc_objfun = false;
201 path->pcc_objfun = OBJFUN_UNDEFINED;
202 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
203 }
204 }
205
206 void copy_candidate_affinity_filters(struct srte_candidate *candidate,
207 struct path *path)
208 {
209 bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
210 bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
211 bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
212 path->has_affinity_filters = eany || iany || iall;
213 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
214 eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
215 - 1]
216 : 0;
217 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
218 iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
219 - 1]
220 : 0;
221 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
222 iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
223 - 1]
224 : 0;
225 }
226
227 struct path_hop *
228 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
229 {
230 struct srte_segment_entry *segment;
231 struct path_hop *hop = NULL, *last_hop = NULL;
232
233 RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
234 &segment_list->segments) {
235 hop = pcep_new_hop();
236 *hop = (struct path_hop){
237 .next = last_hop,
238 .is_loose = false,
239 .has_sid = true,
240 .is_mpls = true,
241 .has_attribs = false,
242 .sid = {.mpls = {.label = segment->sid_value}},
243 .has_nai =
244 segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
245 .nai = {.type = pcep_nai_type(segment->nai_type)}};
246 switch (segment->nai_type) {
247 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
248 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
249 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
250 sizeof(struct ipaddr));
251 break;
252 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
253 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
254 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
255 sizeof(struct ipaddr));
256 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
257 sizeof(struct ipaddr));
258 break;
259 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
260 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
261 sizeof(struct ipaddr));
262 hop->nai.local_iface = segment->nai_local_iface;
263 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
264 sizeof(struct ipaddr));
265 hop->nai.remote_iface = segment->nai_remote_iface;
266 break;
267 default:
268 break;
269 }
270 last_hop = hop;
271 }
272 return hop;
273 }
274
275 int path_pcep_config_update_path(struct path *path)
276 {
277 assert(path != NULL);
278 assert(path->nbkey.preference != 0);
279 assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
280
281 struct path_hop *hop;
282 struct path_metric *metric;
283 int index;
284 char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
285 char *segment_list_name = NULL;
286 struct srte_candidate *candidate;
287 struct srte_segment_list *segment_list = NULL;
288 struct srte_segment_entry *segment;
289
290 candidate = lookup_candidate(&path->nbkey);
291
292 // if there is no candidate to update we are done
293 if (!candidate)
294 return 0;
295
296 // first clean up old segment list if present
297 if (candidate->lsp->segment_list) {
298 SET_FLAG(candidate->lsp->segment_list->flags,
299 F_SEGMENT_LIST_DELETED);
300 candidate->lsp->segment_list = NULL;
301 }
302
303 if (path->first_hop != NULL) {
304 snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
305 "%s-%u", path->name, path->plsp_id);
306 segment_list_name = segment_list_name_buff;
307
308 segment_list = srte_segment_list_add(segment_list_name);
309 segment_list->protocol_origin = path->update_origin;
310 strlcpy(segment_list->originator, path->originator,
311 sizeof(segment_list->originator));
312 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
313 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
314
315 for (hop = path->first_hop, index = 10; hop != NULL;
316 hop = hop->next, index += 10) {
317 assert(hop->has_sid);
318 assert(hop->is_mpls);
319
320 segment = srte_segment_entry_add(segment_list, index);
321
322 segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
323 SET_FLAG(segment->segment_list->flags,
324 F_SEGMENT_LIST_MODIFIED);
325
326 if (hop->has_nai)
327 srte_segment_entry_set_nai(
328 segment, srte_nai_type(hop->nai.type),
329 &hop->nai.local_addr,
330 hop->nai.local_iface,
331 &hop->nai.remote_addr,
332 hop->nai.remote_iface);
333 }
334 }
335
336 candidate->lsp->segment_list = segment_list;
337 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
338
339 for (metric = path->first_metric; metric != NULL; metric = metric->next)
340 srte_lsp_set_metric(
341 candidate->lsp,
342 (enum srte_candidate_metric_type)metric->type,
343 metric->value, metric->enforce, metric->is_bound,
344 metric->is_computed);
345
346 if (path->has_bandwidth)
347 srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
348 path->enforce_bandwidth);
349
350 if (path->has_pce_objfun) {
351 SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
352 candidate->lsp->objfun = path->pce_objfun;
353 }
354
355 srte_apply_changes();
356
357 return 0;
358 }
359
360 struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
361 {
362 struct srte_policy *policy = NULL;
363 policy = srte_policy_find(key->color, &key->endpoint);
364 if (policy == NULL)
365 return NULL;
366 return srte_candidate_find(policy, key->preference);
367 }
368
369 char *candidate_name(struct srte_candidate *candidate)
370 {
371 return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
372 candidate->name);
373 }
374
375 enum pcep_lsp_operational_status
376 status_int_to_ext(enum srte_policy_status status)
377 {
378 switch (status) {
379 case SRTE_POLICY_STATUS_UP:
380 return PCEP_LSP_OPERATIONAL_ACTIVE;
381 case SRTE_POLICY_STATUS_GOING_UP:
382 return PCEP_LSP_OPERATIONAL_GOING_UP;
383 case SRTE_POLICY_STATUS_GOING_DOWN:
384 return PCEP_LSP_OPERATIONAL_GOING_DOWN;
385 default:
386 return PCEP_LSP_OPERATIONAL_DOWN;
387 }
388 }
389
390 enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
391 {
392 switch (type) {
393 case SRTE_SEGMENT_NAI_TYPE_NONE:
394 return PCEP_SR_SUBOBJ_NAI_ABSENT;
395 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
396 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
397 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
398 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
399 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
400 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
401 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
402 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
403 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
404 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
405 default:
406 return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
407 }
408 }
409
410 enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
411 {
412 switch (type) {
413 case PCEP_SR_SUBOBJ_NAI_ABSENT:
414 return SRTE_SEGMENT_NAI_TYPE_NONE;
415 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
416 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
417 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
418 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
419 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
420 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
421 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
422 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
423 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
424 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
425 default:
426 return SRTE_SEGMENT_NAI_TYPE_NONE;
427 }
428 }