]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_config.c
*: Convert event.h to frrevent.h
[mirror_frr.git] / pathd / path_pcep_config.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2020 NetDEF, Inc.
4 */
5
6 #include <zebra.h>
7
8 #include <northbound.h>
9 #include <yang.h>
10 #include <printfrr.h>
11 #include "pceplib/pcep_msg_objects.h"
12 #include "pathd/pathd.h"
13 #include "pathd/path_pcep.h"
14 #include "pathd/path_pcep_config.h"
15 #include "pathd/path_pcep_debug.h"
16 #include "frrevent.h"
17
18 #define MAX_XPATH 256
19 #define MAX_FLOAT_LEN 22
20 #define INETADDR4_MAXLEN 16
21 #define INETADDR6_MAXLEN 40
22 #define INITIATED_CANDIDATE_PREFERENCE 255
23 #define INITIATED_POLICY_COLOR 1
24
25
26 static void copy_candidate_objfun_info(struct srte_candidate *candidate,
27 struct path *path);
28 static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
29 struct path *path);
30 static struct path_hop *
31 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
32 static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
33 static char *candidate_name(struct srte_candidate *candidate);
34 static enum pcep_lsp_operational_status
35 status_int_to_ext(enum srte_policy_status status);
36 static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
37 static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
38
39 void path_pcep_refine_path(struct path *path)
40 {
41 struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
42 struct srte_lsp *lsp;
43
44 if (candidate == NULL)
45 return;
46
47 lsp = candidate->lsp;
48
49 if (path->name == NULL)
50 path->name = candidate_name(candidate);
51 if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
52 path->type = candidate->type;
53 if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
54 path->create_origin = candidate->protocol_origin;
55 if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
56 && (lsp->segment_list != NULL))
57 path->update_origin = lsp->segment_list->protocol_origin;
58 }
59
60 struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
61 {
62 struct srte_candidate *candidate = lookup_candidate(key);
63 if (candidate == NULL)
64 return NULL;
65 return candidate_to_path(candidate);
66 }
67
68 void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
69 {
70 struct path *path;
71 struct srte_policy *policy;
72 struct srte_candidate *candidate;
73
74 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
75 RB_FOREACH (candidate, srte_candidate_head,
76 &policy->candidate_paths) {
77 path = candidate_to_path(candidate);
78 if (!cb(path, arg))
79 return;
80 }
81 }
82 }
83
84 struct path *candidate_to_path(struct srte_candidate *candidate)
85 {
86 char *name;
87 struct path *path;
88 struct path_hop *hop = NULL;
89 struct path_metric *metric = NULL;
90 struct srte_policy *policy;
91 struct srte_lsp *lsp;
92 enum pcep_lsp_operational_status status;
93 enum srte_protocol_origin update_origin = 0;
94 char *originator = NULL;
95
96 policy = candidate->policy;
97 lsp = candidate->lsp;
98
99 if (lsp->segment_list != NULL) {
100 hop = path_pcep_config_list_path_hops(lsp->segment_list);
101 update_origin = lsp->segment_list->protocol_origin;
102 originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
103 }
104 path = pcep_new_path();
105 name = candidate_name(candidate);
106 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
107 status = status_int_to_ext(policy->status);
108 } else {
109 status = PCEP_LSP_OPERATIONAL_DOWN;
110 }
111 for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
112 struct path_metric *path_metric;
113 struct srte_metric *srte_metric = &lsp->metrics[i];
114 if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
115 path_metric = pcep_new_metric();
116 path_metric->next = metric;
117 metric = path_metric;
118 metric->type = i + 1;
119 metric->value = srte_metric->value;
120 metric->enforce = CHECK_FLAG(srte_metric->flags,
121 F_METRIC_IS_REQUIRED);
122 metric->is_bound = CHECK_FLAG(srte_metric->flags,
123 F_METRIC_IS_BOUND);
124 metric->is_computed = CHECK_FLAG(srte_metric->flags,
125 F_METRIC_IS_COMPUTED);
126 }
127 }
128 *path = (struct path){
129 .nbkey = (struct lsp_nb_key){.color = policy->color,
130 .endpoint = policy->endpoint,
131 .preference =
132 candidate->preference},
133 .create_origin = lsp->protocol_origin,
134 .update_origin = update_origin,
135 .originator = originator,
136 .plsp_id = 0,
137 .name = name,
138 .type = candidate->type,
139 .srp_id = policy->srp_id,
140 .req_id = 0,
141 .binding_sid = policy->binding_sid,
142 .status = status,
143 .do_remove = false,
144 .go_active = false,
145 .was_created = false,
146 .was_removed = false,
147 .is_synching = false,
148 .is_delegated = false,
149 .first_hop = hop,
150 .first_metric = metric};
151
152 path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
153 if (path->has_bandwidth) {
154 path->enforce_bandwidth =
155 CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
156 path->bandwidth = lsp->bandwidth;
157 } else {
158 path->enforce_bandwidth = true;
159 path->bandwidth = 0;
160 }
161
162 copy_candidate_objfun_info(candidate, path);
163 copy_candidate_affinity_filters(candidate, path);
164
165 return path;
166 }
167
168 void copy_candidate_objfun_info(struct srte_candidate *candidate,
169 struct path *path)
170 {
171 struct srte_lsp *lsp = candidate->lsp;
172
173 if (lsp != NULL) {
174 if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
175 path->has_pce_objfun = true;
176 path->pce_objfun = lsp->objfun;
177 } else {
178 path->has_pce_objfun = false;
179 path->pce_objfun = OBJFUN_UNDEFINED;
180 }
181 }
182 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
183 path->has_pcc_objfun = true;
184 path->pcc_objfun = candidate->objfun;
185 path->enforce_pcc_objfun = CHECK_FLAG(
186 candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
187
188 } else {
189 path->has_pcc_objfun = false;
190 path->pcc_objfun = OBJFUN_UNDEFINED;
191 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
192 }
193 }
194
195 void copy_candidate_affinity_filters(struct srte_candidate *candidate,
196 struct path *path)
197 {
198 bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
199 bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
200 bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
201 path->has_affinity_filters = eany || iany || iall;
202 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
203 eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
204 - 1]
205 : 0;
206 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
207 iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
208 - 1]
209 : 0;
210 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
211 iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
212 - 1]
213 : 0;
214 }
215
216 struct path_hop *
217 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
218 {
219 struct srte_segment_entry *segment;
220 struct path_hop *hop = NULL, *last_hop = NULL;
221
222 RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
223 &segment_list->segments) {
224 hop = pcep_new_hop();
225 *hop = (struct path_hop){
226 .next = last_hop,
227 .is_loose = false,
228 .has_sid = true,
229 .is_mpls = true,
230 .has_attribs = false,
231 .sid = {.mpls = {.label = segment->sid_value}},
232 .has_nai =
233 segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
234 .nai = {.type = pcep_nai_type(segment->nai_type)}};
235 switch (segment->nai_type) {
236 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
237 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
238 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
239 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
240 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
241 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
242 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
243 sizeof(struct ipaddr));
244 break;
245 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
246 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
247 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
248 sizeof(struct ipaddr));
249 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
250 sizeof(struct ipaddr));
251 break;
252 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
253 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
254 sizeof(struct ipaddr));
255 hop->nai.local_iface = segment->nai_local_iface;
256 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
257 sizeof(struct ipaddr));
258 hop->nai.remote_iface = segment->nai_remote_iface;
259 break;
260 case SRTE_SEGMENT_NAI_TYPE_NONE:
261 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
262 break;
263 }
264 last_hop = hop;
265 }
266 return hop;
267 }
268
269 int path_pcep_config_initiate_path(struct path *path)
270 {
271 struct srte_policy *policy;
272 struct srte_candidate *candidate;
273
274 if (path->do_remove) {
275 zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
276 path->originator);
277 candidate = lookup_candidate(&path->nbkey);
278 if (candidate) {
279 if (!path->is_delegated) {
280 zlog_warn(
281 "(%s)PCE tried to REMOVE but it's not Delegated!",
282 __func__);
283 return ERROR_19_1;
284 }
285 if (candidate->type != SRTE_CANDIDATE_TYPE_DYNAMIC) {
286 zlog_warn(
287 "(%s)PCE tried to REMOVE but it's not PCE origin!",
288 __func__);
289 return ERROR_19_9;
290 }
291 zlog_warn(
292 "(%s)PCE tried to REMOVE found candidate!, let's remove",
293 __func__);
294 candidate->policy->srp_id = path->srp_id;
295 SET_FLAG(candidate->policy->flags, F_POLICY_DELETED);
296 SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
297 } else {
298 zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
299 __func__);
300 return ERROR_19_3;
301 }
302 srte_apply_changes();
303 } else {
304 assert(!IS_IPADDR_NONE(&path->nbkey.endpoint));
305
306 if (path->nbkey.preference == 0)
307 path->nbkey.preference = INITIATED_CANDIDATE_PREFERENCE;
308
309 if (path->nbkey.color == 0)
310 path->nbkey.color = INITIATED_POLICY_COLOR;
311
312 candidate = lookup_candidate(&path->nbkey);
313 if (!candidate) {
314 policy = srte_policy_add(
315 path->nbkey.color, &path->nbkey.endpoint,
316 SRTE_ORIGIN_PCEP, path->originator);
317 strlcpy(policy->name, path->name, sizeof(policy->name));
318 policy->binding_sid = path->binding_sid;
319 SET_FLAG(policy->flags, F_POLICY_NEW);
320 candidate = srte_candidate_add(
321 policy, path->nbkey.preference,
322 SRTE_ORIGIN_PCEP, path->originator);
323 candidate->policy->srp_id = path->srp_id;
324 strlcpy(candidate->name, path->name,
325 sizeof(candidate->name));
326 SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
327 } else {
328 policy = candidate->policy;
329 if ((path->originator != candidate->originator)
330 || (path->originator != policy->originator)) {
331 /* There is already an initiated path from
332 * another PCE, show a warning and regect the
333 * initiated path */
334 zlog_warn(
335 "PCE %s tried to initiate a path already initiated by PCE %s",
336 path->originator,
337 candidate->originator);
338 return 1;
339 }
340 if ((policy->protocol_origin != SRTE_ORIGIN_PCEP)
341 || (candidate->protocol_origin
342 != SRTE_ORIGIN_PCEP)) {
343 /* There is already an initiated path from
344 * another PCE, show a warning and regect the
345 * initiated path */
346 zlog_warn(
347 "PCE %s tried to initiate a path created localy",
348 path->originator);
349 return 1;
350 }
351 }
352 return path_pcep_config_update_path(path);
353 }
354 return 0;
355 }
356
357 int path_pcep_config_update_path(struct path *path)
358 {
359 assert(path != NULL);
360 assert(path->nbkey.preference != 0);
361 assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
362
363 int number_of_sid_clashed = 0;
364 struct path_hop *hop;
365 struct path_metric *metric;
366 int index;
367 char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
368 char *segment_list_name = NULL;
369 struct srte_candidate *candidate;
370 struct srte_segment_list *segment_list = NULL;
371 struct srte_segment_entry *segment;
372
373 candidate = lookup_candidate(&path->nbkey);
374
375 // if there is no candidate to update we are done
376 if (!candidate)
377 return 0;
378
379 candidate->policy->srp_id = path->srp_id;
380 // first clean up old segment list if present
381 if (candidate->lsp->segment_list) {
382 SET_FLAG(candidate->lsp->segment_list->flags,
383 F_SEGMENT_LIST_DELETED);
384 srte_segment_list_del(candidate->lsp->segment_list);
385 candidate->lsp->segment_list = NULL;
386 }
387
388 if (path->first_hop == NULL)
389 return PATH_NB_ERR;
390
391 snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
392 "%s-%u", path->name, path->plsp_id);
393 segment_list_name = segment_list_name_buff;
394
395 segment_list = srte_segment_list_add(segment_list_name);
396 segment_list->protocol_origin = path->update_origin;
397 strlcpy(segment_list->originator, path->originator,
398 sizeof(segment_list->originator));
399 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
400 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
401
402 for (hop = path->first_hop, index = 10; hop != NULL;
403 hop = hop->next, index += 10) {
404 assert(hop->has_sid);
405 assert(hop->is_mpls);
406
407 segment = srte_segment_entry_add(segment_list, index);
408
409 segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
410 SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
411
412 if (!hop->has_nai)
413 continue;
414 if (srte_segment_entry_set_nai(
415 segment, srte_nai_type(hop->nai.type),
416 &hop->nai.local_addr, hop->nai.local_iface,
417 &hop->nai.remote_addr, hop->nai.remote_iface, 0, 0)
418 == PATH_SID_ERROR)
419 /* TED queries don't match PCE */
420 /* Don't apply srte,zebra changes */
421 number_of_sid_clashed++;
422 }
423
424 candidate->lsp->segment_list = segment_list;
425 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
426
427 for (metric = path->first_metric; metric != NULL; metric = metric->next)
428 srte_lsp_set_metric(
429 candidate->lsp,
430 (enum srte_candidate_metric_type)metric->type,
431 metric->value, metric->enforce, metric->is_bound,
432 metric->is_computed);
433
434 if (path->has_bandwidth)
435 srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
436 path->enforce_bandwidth);
437
438 if (path->has_pce_objfun) {
439 SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
440 candidate->lsp->objfun = path->pce_objfun;
441 }
442
443 if (number_of_sid_clashed)
444 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
445 else
446 srte_apply_changes();
447
448 return 0;
449 }
450
451 struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
452 {
453 struct srte_policy *policy = NULL;
454 policy = srte_policy_find(key->color, &key->endpoint);
455 if (policy == NULL)
456 return NULL;
457 return srte_candidate_find(policy, key->preference);
458 }
459
460 char *candidate_name(struct srte_candidate *candidate)
461 {
462 if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
463 || candidate->protocol_origin == SRTE_ORIGIN_BGP)
464 return asprintfrr(MTYPE_PCEP, "%s", candidate->policy->name);
465 else
466 return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
467 candidate->name);
468 }
469
470 enum pcep_lsp_operational_status
471 status_int_to_ext(enum srte_policy_status status)
472 {
473 switch (status) {
474 case SRTE_POLICY_STATUS_UP:
475 return PCEP_LSP_OPERATIONAL_ACTIVE;
476 case SRTE_POLICY_STATUS_GOING_UP:
477 return PCEP_LSP_OPERATIONAL_GOING_UP;
478 case SRTE_POLICY_STATUS_GOING_DOWN:
479 return PCEP_LSP_OPERATIONAL_GOING_DOWN;
480 case SRTE_POLICY_STATUS_DOWN:
481 case SRTE_POLICY_STATUS_UNKNOWN:
482 return PCEP_LSP_OPERATIONAL_DOWN;
483 }
484
485 assert(!"Reached end of function where we are not expecting to");
486 }
487
488 enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
489 {
490 switch (type) {
491 case SRTE_SEGMENT_NAI_TYPE_NONE:
492 return PCEP_SR_SUBOBJ_NAI_ABSENT;
493 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
494 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
495 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
496 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
497 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
498 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
499 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
500 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
501 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
502 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
503 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
504 return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY;
505 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
506 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
507 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
508 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
509 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
510 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
511 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
512 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
513 default:
514 return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
515 }
516 }
517
518 enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
519 {
520 switch (type) {
521 case PCEP_SR_SUBOBJ_NAI_ABSENT:
522 return SRTE_SEGMENT_NAI_TYPE_NONE;
523 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
524 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
525 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
526 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
527 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
528 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
529 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
530 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
531 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
532 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
533 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY:
534 case PCEP_SR_SUBOBJ_NAI_UNKNOWN:
535 return SRTE_SEGMENT_NAI_TYPE_NONE;
536 }
537
538 assert(!"Reached end of function where we were not expecting to");
539 }