]> git.proxmox.com Git - mirror_frr.git/blob - pathd/pathd.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / pathd / pathd.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 "memory.h"
9 #include "log.h"
10 #include "lib_errors.h"
11 #include "network.h"
12 #include "libfrr.h"
13 #include <debug.h>
14 #include <hook.h>
15
16 #include "pathd/pathd.h"
17 #include "pathd/path_zebra.h"
18 #include "pathd/path_debug.h"
19 #include "pathd/path_ted.h"
20
21 #define HOOK_DELAY 3
22
23 DEFINE_MGROUP(PATHD, "pathd");
24
25 DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List");
26 DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy");
27 DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path");
28
29 DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
30 (candidate));
31 DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
32 (candidate));
33 DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
34 (candidate));
35
36 struct debug path_policy_debug;
37
38 #define PATH_POLICY_DEBUG(fmt, ...) \
39 do { \
40 if (DEBUG_FLAGS_CHECK(&path_policy_debug, \
41 PATH_POLICY_DEBUG_BASIC)) \
42 DEBUGD(&path_policy_debug, "policy: " fmt, \
43 ##__VA_ARGS__); \
44 } while (0)
45
46
47 static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
48 static void trigger_pathd_candidate_created_timer(struct thread *thread);
49 static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
50 static void trigger_pathd_candidate_updated_timer(struct thread *thread);
51 static void trigger_pathd_candidate_removed(struct srte_candidate *candidate);
52 static const char *
53 srte_candidate_metric_name(enum srte_candidate_metric_type type);
54
55 static void srte_set_metric(struct srte_metric *metric, float value,
56 bool required, bool is_bound, bool is_computed);
57 static void srte_unset_metric(struct srte_metric *metric);
58
59
60 /* Generate rb-tree of Segment List Segment instances. */
61 static inline int srte_segment_entry_compare(const struct srte_segment_entry *a,
62 const struct srte_segment_entry *b)
63 {
64 return a->index - b->index;
65 }
66 RB_GENERATE(srte_segment_entry_head, srte_segment_entry, entry,
67 srte_segment_entry_compare)
68
69 /* Generate rb-tree of Segment List instances. */
70 static inline int srte_segment_list_compare(const struct srte_segment_list *a,
71 const struct srte_segment_list *b)
72 {
73 return strcmp(a->name, b->name);
74 }
75 RB_GENERATE(srte_segment_list_head, srte_segment_list, entry,
76 srte_segment_list_compare)
77
78 struct srte_segment_list_head srte_segment_lists =
79 RB_INITIALIZER(&srte_segment_lists);
80
81 /* Generate rb-tree of Candidate Path instances. */
82 static inline int srte_candidate_compare(const struct srte_candidate *a,
83 const struct srte_candidate *b)
84 {
85 return a->preference - b->preference;
86 }
87 RB_GENERATE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
88
89 /* Generate rb-tree of SR Policy instances. */
90 static inline int srte_policy_compare(const struct srte_policy *a,
91 const struct srte_policy *b)
92 {
93 return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
94 b->color);
95 }
96 RB_GENERATE(srte_policy_head, srte_policy, entry, srte_policy_compare)
97
98 struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
99
100 static void srte_policy_status_log(struct srte_policy *policy)
101 {
102 char endpoint[ENDPOINT_STR_LENGTH];
103
104 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
105 if (policy->status == SRTE_POLICY_STATUS_DOWN) {
106 PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is DOWN", endpoint,
107 policy->color);
108 } else if (policy->status == SRTE_POLICY_STATUS_UP) {
109 PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is UP", endpoint,
110 policy->color);
111 }
112 }
113
114 /**
115 * Adds a segment list to pathd.
116 *
117 * @param name The name of the segment list to add
118 * @return The added segment list
119 */
120 struct srte_segment_list *srte_segment_list_add(const char *name)
121 {
122 struct srte_segment_list *segment_list;
123
124 segment_list = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment_list));
125 strlcpy(segment_list->name, name, sizeof(segment_list->name));
126 RB_INIT(srte_segment_entry_head, &segment_list->segments);
127 RB_INSERT(srte_segment_list_head, &srte_segment_lists, segment_list);
128
129 return segment_list;
130 }
131
132 /**
133 * Deletes a segment list from pathd.
134 *
135 * The given segment list structure will be freed and should not be used anymore
136 * after calling this function.
137 *
138 * @param segment_list the segment list to remove from pathd.
139 */
140 void srte_segment_list_del(struct srte_segment_list *segment_list)
141 {
142 struct srte_segment_entry *segment, *safe_seg;
143 RB_FOREACH_SAFE (segment, srte_segment_entry_head,
144 &segment_list->segments, safe_seg) {
145 srte_segment_entry_del(segment);
146 }
147 RB_REMOVE(srte_segment_list_head, &srte_segment_lists, segment_list);
148 XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list);
149 }
150
151 /**
152 * Search for a segment list by name.
153 *
154 * @param name The name of the segment list to look for
155 * @return The segment list if found, NULL otherwise
156 */
157 struct srte_segment_list *srte_segment_list_find(const char *name)
158 {
159 struct srte_segment_list search;
160
161 strlcpy(search.name, name, sizeof(search.name));
162 return RB_FIND(srte_segment_list_head, &srte_segment_lists, &search);
163 }
164
165 /**
166 * Adds a segment to a segment list.
167 *
168 * @param segment_list The segment list the segment should be added to
169 * @param index The index of the added segment in the segment list
170 * @return The added segment
171 */
172 struct srte_segment_entry *
173 srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index)
174 {
175 struct srte_segment_entry *segment;
176
177 segment = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment));
178 segment->segment_list = segment_list;
179 segment->index = index;
180 RB_INSERT(srte_segment_entry_head, &segment_list->segments, segment);
181
182 return segment;
183 }
184
185 /**
186 * Deletes a segment from a segment list.
187 *
188 * @param segment The segment to be removed
189 */
190 void srte_segment_entry_del(struct srte_segment_entry *segment)
191 {
192 RB_REMOVE(srte_segment_entry_head, &segment->segment_list->segments,
193 segment);
194 XFREE(MTYPE_PATH_SEGMENT_LIST, segment);
195 }
196
197 /**
198 * Set the node or adjacency identifier of a segment.
199 *
200 * @param segment The segment for which the NAI should be set
201 * @param type The type of the NAI
202 * @param type The address of the node or the local address of the adjacency
203 * @param type The local interface index of the unumbered adjacency
204 * @param type The remote address of the adjacency
205 * @param type The remote interface index of the unumbered adjacency
206 */
207 int srte_segment_entry_set_nai(struct srte_segment_entry *segment,
208 enum srte_segment_nai_type type,
209 struct ipaddr *local_ip, uint32_t local_iface,
210 struct ipaddr *remote_ip, uint32_t remote_iface,
211 uint8_t algo, uint8_t pref_len)
212 {
213
214 int32_t status = 0;
215 struct prefix pre = {0};
216
217 if (!segment || !local_ip || !remote_ip)
218 return 1;
219
220 segment->nai_type = type;
221 memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr));
222
223 switch (type) {
224 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
225 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
226 break;
227 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
228 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
229 memcpy(&segment->nai_remote_addr, remote_ip,
230 sizeof(struct ipaddr));
231 status = srte_ted_do_query_type_f(segment, local_ip, remote_ip);
232 break;
233 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
234 memcpy(&segment->nai_remote_addr, remote_ip,
235 sizeof(struct ipaddr));
236 segment->nai_local_iface = local_iface;
237 segment->nai_remote_iface = remote_iface;
238 break;
239 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
240 pre.family = AF_INET6;
241 pre.prefixlen = pref_len;
242 pre.u.prefix6 = local_ip->ip._v6_addr;
243 segment->nai_local_prefix_len = pref_len;
244 segment->nai_algorithm = algo;
245 status = srte_ted_do_query_type_c(segment, &pre, algo);
246 break;
247 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
248 pre.family = AF_INET;
249 pre.prefixlen = pref_len;
250 pre.u.prefix4 = local_ip->ip._v4_addr;
251 segment->nai_local_prefix_len = pref_len;
252 segment->nai_algorithm = algo;
253 status = srte_ted_do_query_type_c(segment, &pre, algo);
254 break;
255 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
256 pre.family = AF_INET6;
257 pre.prefixlen = pref_len;
258 pre.u.prefix6 = local_ip->ip._v6_addr;
259 segment->nai_local_prefix_len = pref_len;
260 segment->nai_local_iface = local_iface;
261 status = srte_ted_do_query_type_e(segment, &pre, local_iface);
262 break;
263 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
264 pre.family = AF_INET;
265 pre.prefixlen = pref_len;
266 pre.u.prefix4 = local_ip->ip._v4_addr;
267 segment->nai_local_prefix_len = pref_len;
268 segment->nai_local_iface = local_iface;
269 status = srte_ted_do_query_type_e(segment, &pre, local_iface);
270 break;
271 case SRTE_SEGMENT_NAI_TYPE_NONE:
272 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
273 segment->nai_local_addr.ipa_type = IPADDR_NONE;
274 segment->nai_local_iface = 0;
275 segment->nai_remote_addr.ipa_type = IPADDR_NONE;
276 segment->nai_remote_iface = 0;
277 }
278 return status;
279 }
280
281 /**
282 * Mark segment as modified depending in protocol and sid conditions
283 *
284 * @param protocol_origin Origin of the segment list
285 * @param s_list Ptr to segment list with flags,sid to modidy
286 * @param s_entry Ptr to segment entry with sid to modidy
287 * @param ted_sid The sid from ted query
288 * @return void
289 */
290 void srte_segment_set_local_modification(struct srte_segment_list *s_list,
291 struct srte_segment_entry *s_entry,
292 uint32_t ted_sid)
293 {
294 if (!s_list || !s_entry)
295 return;
296
297 if (s_list->protocol_origin == SRTE_ORIGIN_LOCAL
298 && s_entry->sid_value != ted_sid) {
299 s_entry->sid_value = ted_sid;
300 SET_FLAG(s_list->flags, F_SEGMENT_LIST_MODIFIED);
301 }
302 }
303
304 /**
305 * Add a policy to pathd.
306 *
307 * WARNING: The color 0 is a special case as it is the no-color.
308 *
309 * @param color The color of the policy.
310 * @param endpoint The IP address of the policy endpoint
311 * @return The created policy
312 */
313 struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint,
314 enum srte_protocol_origin origin,
315 const char *originator)
316 {
317 struct srte_policy *policy;
318
319 policy = XCALLOC(MTYPE_PATH_SR_POLICY, sizeof(*policy));
320 policy->color = color;
321 policy->endpoint = *endpoint;
322 policy->binding_sid = MPLS_LABEL_NONE;
323 policy->protocol_origin = origin;
324 if (originator != NULL)
325 strlcpy(policy->originator, originator,
326 sizeof(policy->originator));
327
328 RB_INIT(srte_candidate_head, &policy->candidate_paths);
329 RB_INSERT(srte_policy_head, &srte_policies, policy);
330
331 return policy;
332 }
333
334 /**
335 * Delete a policy from pathd.
336 *
337 * The given policy structure will be freed and should never be used again
338 * after calling this function.
339 *
340 * @param policy The policy to be removed
341 */
342 void srte_policy_del(struct srte_policy *policy)
343 {
344 struct srte_candidate *candidate;
345
346 path_zebra_delete_sr_policy(policy);
347
348 path_zebra_release_label(policy->binding_sid);
349
350 while (!RB_EMPTY(srte_candidate_head, &policy->candidate_paths)) {
351 candidate =
352 RB_ROOT(srte_candidate_head, &policy->candidate_paths);
353 trigger_pathd_candidate_removed(candidate);
354 srte_candidate_del(candidate);
355 }
356
357 RB_REMOVE(srte_policy_head, &srte_policies, policy);
358 XFREE(MTYPE_PATH_SR_POLICY, policy);
359 }
360
361 /**
362 * Search for a policy by color and endpoint.
363 *
364 * WARNING: The color 0 is a special case as it is the no-color.
365 *
366 * @param color The color of the policy to look for
367 * @param endpoint The endpoint of the policy to look for
368 * @return The policy if found, NULL otherwise
369 */
370 struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint)
371 {
372 struct srte_policy search;
373
374 search.color = color;
375 search.endpoint = *endpoint;
376 return RB_FIND(srte_policy_head, &srte_policies, &search);
377 }
378
379 /*
380 * After new data from igp,local and pce the segment list :
381 * Mark as invalid for origin pce if cannot be validated
382 * Updated for origin local
383 */
384 int srte_policy_update_ted_sid(void)
385 {
386
387 int number_of_sid_clashed = 0;
388 struct srte_segment_list *s_list;
389 struct srte_segment_entry *s_entry;
390
391 if (!path_ted_is_initialized())
392 return 0;
393 if (RB_EMPTY(srte_segment_list_head, &srte_segment_lists))
394 return 0;
395
396 RB_FOREACH (s_list, srte_segment_list_head, &srte_segment_lists) {
397 if (CHECK_FLAG(s_list->flags, F_SEGMENT_LIST_DELETED))
398 continue;
399 RB_FOREACH (s_entry, srte_segment_entry_head,
400 &s_list->segments) {
401 PATH_TED_DEBUG(
402 "%s:PATHD-TED: SL: Name: %s index:(%d) sid:(%d) prefix_len:(%d) local iface:(%d) algorithm:(%d)",
403 __func__, s_list->name, s_entry->index,
404 s_entry->sid_value,
405 s_entry->nai_local_prefix_len,
406 s_entry->nai_local_iface,
407 s_entry->nai_algorithm);
408 struct prefix prefix_cli = {0};
409
410 switch (s_entry->nai_type) {
411 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
412 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
413 number_of_sid_clashed +=
414 srte_ted_do_query_type_f(
415 s_entry,
416 &s_entry->nai_local_addr,
417 &s_entry->nai_remote_addr);
418 break;
419 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
420 prefix_cli.family = AF_INET6;
421 prefix_cli.prefixlen =
422 s_entry->nai_local_prefix_len;
423 prefix_cli.u.prefix6 =
424 s_entry->nai_local_addr.ip._v6_addr;
425 number_of_sid_clashed +=
426 srte_ted_do_query_type_e(
427 s_entry, &prefix_cli,
428 s_entry->nai_local_iface);
429 break;
430 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
431 prefix_cli.family = AF_INET;
432 prefix_cli.prefixlen =
433 s_entry->nai_local_prefix_len;
434 prefix_cli.u.prefix4 =
435 s_entry->nai_local_addr.ip._v4_addr;
436 number_of_sid_clashed +=
437 srte_ted_do_query_type_e(
438 s_entry, &prefix_cli,
439 s_entry->nai_local_iface);
440 break;
441 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
442 prefix_cli.family = AF_INET6;
443 prefix_cli.prefixlen =
444 s_entry->nai_local_prefix_len;
445 prefix_cli.u.prefix6 =
446 s_entry->nai_local_addr.ip._v6_addr;
447 number_of_sid_clashed +=
448 srte_ted_do_query_type_c(
449 s_entry, &prefix_cli,
450 s_entry->nai_algorithm);
451 break;
452 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
453 prefix_cli.family = AF_INET;
454 prefix_cli.prefixlen =
455 s_entry->nai_local_prefix_len;
456 prefix_cli.u.prefix4 =
457 s_entry->nai_local_addr.ip._v4_addr;
458 number_of_sid_clashed +=
459 srte_ted_do_query_type_c(
460 s_entry, &prefix_cli,
461 s_entry->nai_algorithm);
462 break;
463 case SRTE_SEGMENT_NAI_TYPE_NONE:
464 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
465 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
466 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
467 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
468 break;
469 }
470 }
471 if (number_of_sid_clashed) {
472 SET_FLAG(s_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
473 number_of_sid_clashed = 0;
474 } else
475 UNSET_FLAG(s_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
476 }
477 srte_apply_changes();
478
479 return 0;
480 }
481
482 /**
483 * Update a policy binding SID.
484 *
485 * @param policy The policy for which the SID should be updated
486 * @param binding_sid The new binding SID for the given policy
487 */
488 void srte_policy_update_binding_sid(struct srte_policy *policy,
489 uint32_t binding_sid)
490 {
491 if (policy->binding_sid != MPLS_LABEL_NONE)
492 path_zebra_release_label(policy->binding_sid);
493
494 policy->binding_sid = binding_sid;
495
496 /* Reinstall the Binding-SID if necessary. */
497 if (policy->best_candidate)
498 path_zebra_add_sr_policy(
499 policy, policy->best_candidate->lsp->segment_list);
500 }
501
502 /**
503 * Gives the policy best candidate path.
504 *
505 * @param policy The policy we want the best candidate path from
506 * @return The best candidate path
507 */
508 static struct srte_candidate *
509 srte_policy_best_candidate(const struct srte_policy *policy)
510 {
511 struct srte_candidate *candidate;
512
513 RB_FOREACH_REVERSE (candidate, srte_candidate_head,
514 &policy->candidate_paths) {
515 /* search for highest preference with existing segment list */
516 if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)
517 && candidate->lsp->segment_list
518 && (!CHECK_FLAG(candidate->lsp->segment_list->flags,
519 F_SEGMENT_LIST_SID_CONFLICT)))
520 return candidate;
521 }
522
523 return NULL;
524 }
525
526 void srte_clean_zebra(void)
527 {
528 struct srte_policy *policy, *safe_pol;
529
530 RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol)
531 srte_policy_del(policy);
532
533 path_zebra_stop();
534 }
535
536 /**
537 * Apply changes defined by setting the policies, candidate paths
538 * and segment lists modification flags NEW, MODIFIED and DELETED.
539 *
540 * This allows the northbound code to delay all the side effects of adding
541 * modifying and deleting them to the end.
542 *
543 * Example of marking an object as modified:
544 * `SET_FLAG(obj->flags, F_XXX_MODIFIED)`
545 */
546 void srte_apply_changes(void)
547 {
548 struct srte_policy *policy, *safe_pol;
549 struct srte_segment_list *segment_list, *safe_sl;
550
551 RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
552 if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
553 if (policy->status != SRTE_POLICY_STATUS_DOWN) {
554 policy->status = SRTE_POLICY_STATUS_DOWN;
555 srte_policy_status_log(policy);
556 }
557 srte_policy_del(policy);
558 continue;
559 }
560 srte_policy_apply_changes(policy);
561 UNSET_FLAG(policy->flags, F_POLICY_NEW);
562 UNSET_FLAG(policy->flags, F_POLICY_MODIFIED);
563 }
564
565 RB_FOREACH_SAFE (segment_list, srte_segment_list_head,
566 &srte_segment_lists, safe_sl) {
567 if (CHECK_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED)) {
568 srte_segment_list_del(segment_list);
569 continue;
570 }
571 UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
572 UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
573 }
574 }
575
576 /**
577 * Apply changes defined by setting the given policy and its candidate paths
578 * modification flags NEW, MODIFIED and DELETED.
579 *
580 * In moste cases `void srte_apply_changes(void)` should be used instead,
581 * this function will not handle the changes of segment lists used by the
582 * policy.
583 *
584 * @param policy The policy changes has to be applied to.
585 */
586 void srte_policy_apply_changes(struct srte_policy *policy)
587 {
588 struct srte_candidate *candidate, *safe;
589 struct srte_candidate *old_best_candidate;
590 struct srte_candidate *new_best_candidate;
591 char endpoint[ENDPOINT_STR_LENGTH];
592
593 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
594
595 /* Get old and new best candidate path. */
596 old_best_candidate = policy->best_candidate;
597 new_best_candidate = srte_policy_best_candidate(policy);
598
599 if (new_best_candidate != old_best_candidate) {
600 PATH_POLICY_DEBUG(
601 "SR-TE(%s, %u): best candidate changed from %s to %s",
602 endpoint, policy->color,
603 old_best_candidate ? old_best_candidate->name : "none",
604 new_best_candidate ? new_best_candidate->name : "none");
605
606 if (old_best_candidate) {
607 policy->best_candidate = NULL;
608 UNSET_FLAG(old_best_candidate->flags, F_CANDIDATE_BEST);
609 SET_FLAG(old_best_candidate->flags,
610 F_CANDIDATE_MODIFIED);
611
612 /*
613 * Rely on replace semantics if there's a new best
614 * candidate.
615 */
616 if (!new_best_candidate)
617 path_zebra_delete_sr_policy(policy);
618 }
619 if (new_best_candidate) {
620 policy->best_candidate = new_best_candidate;
621 SET_FLAG(new_best_candidate->flags, F_CANDIDATE_BEST);
622 SET_FLAG(new_best_candidate->flags,
623 F_CANDIDATE_MODIFIED);
624
625 path_zebra_add_sr_policy(
626 policy, new_best_candidate->lsp->segment_list);
627 }
628 } else if (new_best_candidate) {
629 /* The best candidate path did not change, but some of its
630 * attributes or its segment list may have changed.
631 */
632
633 bool candidate_changed = CHECK_FLAG(new_best_candidate->flags,
634 F_CANDIDATE_MODIFIED);
635 bool segment_list_changed =
636 new_best_candidate->lsp->segment_list
637 && CHECK_FLAG(
638 new_best_candidate->lsp->segment_list->flags,
639 F_SEGMENT_LIST_MODIFIED);
640
641 if (candidate_changed || segment_list_changed) {
642 PATH_POLICY_DEBUG(
643 "SR-TE(%s, %u): best candidate %s changed",
644 endpoint, policy->color,
645 new_best_candidate->name);
646
647 path_zebra_add_sr_policy(
648 policy, new_best_candidate->lsp->segment_list);
649 }
650 }
651
652 RB_FOREACH_SAFE (candidate, srte_candidate_head,
653 &policy->candidate_paths, safe) {
654 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)) {
655 trigger_pathd_candidate_removed(candidate);
656 srte_candidate_del(candidate);
657 continue;
658 } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_NEW)) {
659 trigger_pathd_candidate_created(candidate);
660 } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_MODIFIED)) {
661 trigger_pathd_candidate_updated(candidate);
662 } else if (candidate->lsp->segment_list
663 && CHECK_FLAG(candidate->lsp->segment_list->flags,
664 F_SEGMENT_LIST_MODIFIED)) {
665 trigger_pathd_candidate_updated(candidate);
666 }
667
668 UNSET_FLAG(candidate->flags, F_CANDIDATE_NEW);
669 UNSET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
670 }
671 }
672
673 /**
674 * Adds a candidate path to a policy.
675 *
676 * @param policy The policy the candidate path should be added to
677 * @param preference The preference of the candidate path to be added
678 * @return The added candidate path
679 */
680 struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
681 uint32_t preference,
682 enum srte_protocol_origin origin,
683 const char *originator)
684 {
685 struct srte_candidate *candidate;
686 struct srte_lsp *lsp;
687
688 candidate = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*candidate));
689 lsp = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*lsp));
690
691 candidate->preference = preference;
692 candidate->policy = policy;
693 candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
694 candidate->discriminator = frr_weak_random();
695 candidate->protocol_origin = origin;
696 if (originator != NULL) {
697 strlcpy(candidate->originator, originator,
698 sizeof(candidate->originator));
699 lsp->protocol_origin = origin;
700 }
701
702 if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
703 || candidate->protocol_origin == SRTE_ORIGIN_BGP) {
704 candidate->type = SRTE_CANDIDATE_TYPE_DYNAMIC;
705 }
706 lsp->candidate = candidate;
707 candidate->lsp = lsp;
708
709 RB_INSERT(srte_candidate_head, &policy->candidate_paths, candidate);
710
711 return candidate;
712 }
713
714 /**
715 * Deletes a candidate.
716 *
717 * The corresponding LSP will be removed alongside the candidate path.
718 * The given candidate will be freed and shouldn't be used anymore after the
719 * calling this function.
720 *
721 * @param candidate The candidate path to delete
722 */
723 void srte_candidate_del(struct srte_candidate *candidate)
724 {
725 struct srte_policy *srte_policy = candidate->policy;
726
727 RB_REMOVE(srte_candidate_head, &srte_policy->candidate_paths,
728 candidate);
729
730 XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp);
731 XFREE(MTYPE_PATH_SR_CANDIDATE, candidate);
732 }
733
734 /**
735 * Sets the bandwidth constraint of given candidate path.
736 *
737 * The corresponding LSP will be changed too.
738 *
739 * @param candidate The candidate path of which the bandwidth should be changed
740 * @param bandwidth The Bandwidth constraint to set to the candidate path
741 * @param required If the constraint is required (true) or only desired (false)
742 */
743 void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
744 float bandwidth, bool required)
745 {
746 struct srte_policy *policy = candidate->policy;
747 char endpoint[ENDPOINT_STR_LENGTH];
748
749 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
750 PATH_POLICY_DEBUG(
751 "SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
752 endpoint, policy->color, candidate->name,
753 required ? "required " : "", bandwidth);
754 SET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
755 COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
756 candidate->bandwidth = bandwidth;
757
758 srte_lsp_set_bandwidth(candidate->lsp, bandwidth, required);
759 }
760
761 /**
762 * Sets the bandwidth constraint of the given LSP.
763 *
764 * The changes will not be shown as part of the running configuration.
765 *
766 * @param lsp The lsp of which the bandwidth should be changed
767 * @param bandwidth The Bandwidth constraint to set to the candidate path
768 * @param required If the constraint is required (true) or only desired (false)
769 */
770 void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
771 bool required)
772 {
773 struct srte_candidate *candidate = lsp->candidate;
774 struct srte_policy *policy = candidate->policy;
775 char endpoint[ENDPOINT_STR_LENGTH];
776
777 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
778 PATH_POLICY_DEBUG(
779 "SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
780 endpoint, policy->color, candidate->name,
781 required ? "required" : "", bandwidth);
782 SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
783 COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
784 lsp->bandwidth = bandwidth;
785 }
786
787 /**
788 * Remove a candidate path bandwidth constraint.
789 *
790 * The corresponding LSP will be changed too.
791 *
792 * @param candidate The candidate path of which the bandwidth should be removed
793 */
794 void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
795 {
796 struct srte_policy *policy = candidate->policy;
797 char endpoint[ENDPOINT_STR_LENGTH];
798
799 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
800 PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s config bandwidth unset",
801 endpoint, policy->color, candidate->name);
802 UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
803 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
804 candidate->bandwidth = 0;
805 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
806 srte_lsp_unset_bandwidth(candidate->lsp);
807 }
808
809 /**
810 * Remove an LSP bandwidth constraint.
811 *
812 * The changes will not be shown as part of the running configuration.
813 *
814 * @param lsp The lsp of which the bandwidth should be changed
815 */
816 void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
817 {
818 struct srte_candidate *candidate = lsp->candidate;
819 struct srte_policy *policy = candidate->policy;
820 char endpoint[ENDPOINT_STR_LENGTH];
821
822 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
823 PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s lsp bandwidth unset",
824 endpoint, policy->color, candidate->name);
825 UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
826 UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
827 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
828 lsp->bandwidth = 0;
829 }
830
831 /**
832 * Sets a candidate path metric constraint.
833 *
834 * The corresponding LSP will be changed too.
835 *
836 * @param candidate The candidate path of which the metric should be changed
837 * @param type The metric type
838 * @param value The metric value
839 * @param required If the constraint is required (true) or only desired (false)
840 * @param is_bound If the metric is an indicative value or a strict upper bound
841 * @param is_computed If the metric was computed or configured
842 */
843 void srte_candidate_set_metric(struct srte_candidate *candidate,
844 enum srte_candidate_metric_type type,
845 float value, bool required, bool is_bound,
846 bool is_computed)
847 {
848 struct srte_policy *policy = candidate->policy;
849 char endpoint[ENDPOINT_STR_LENGTH];
850
851 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
852 PATH_POLICY_DEBUG(
853 "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
854 endpoint, policy->color, candidate->name,
855 required ? "required " : "", srte_candidate_metric_name(type),
856 type, value, is_bound ? "true" : "false",
857 is_computed ? "true" : "false");
858 assert((type > 0) && (type <= MAX_METRIC_TYPE));
859 srte_set_metric(&candidate->metrics[type - 1], value, required,
860 is_bound, is_computed);
861 srte_lsp_set_metric(candidate->lsp, type, value, required, is_bound,
862 is_computed);
863 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
864 }
865
866 /**
867 * Sets an LSP metric constraint.
868 *
869 * The changes will not be shown as part of the running configuration.
870 *
871 * @param lsp The LSP of which the metric should be changed
872 * @param type The metric type
873 * @param value The metric value
874 * @param required If the constraint is required (true) or only desired (false)
875 * @param is_bound If the metric is an indicative value or a strict upper bound
876 * @param is_computed If the metric was computed or configured
877 */
878 void srte_lsp_set_metric(struct srte_lsp *lsp,
879 enum srte_candidate_metric_type type, float value,
880 bool required, bool is_bound, bool is_computed)
881 {
882 struct srte_candidate *candidate = lsp->candidate;
883 struct srte_policy *policy = candidate->policy;
884 char endpoint[ENDPOINT_STR_LENGTH];
885
886 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
887 PATH_POLICY_DEBUG(
888 "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
889 endpoint, policy->color, candidate->name,
890 required ? "required " : "", srte_candidate_metric_name(type),
891 type, value, is_bound ? "true" : "false",
892 is_computed ? "true" : "false");
893 assert((type > 0) && (type <= MAX_METRIC_TYPE));
894 srte_set_metric(&lsp->metrics[type - 1], value, required, is_bound,
895 is_computed);
896 }
897
898 void srte_set_metric(struct srte_metric *metric, float value, bool required,
899 bool is_bound, bool is_computed)
900 {
901 SET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
902 COND_FLAG(metric->flags, F_METRIC_IS_REQUIRED, required);
903 COND_FLAG(metric->flags, F_METRIC_IS_BOUND, is_bound);
904 COND_FLAG(metric->flags, F_METRIC_IS_COMPUTED, is_computed);
905 metric->value = value;
906 }
907
908 /**
909 * Removes a candidate path metric constraint.
910 *
911 * The corresponding LSP will be changed too.
912 *
913 * @param candidate The candidate path from which the metric should be removed
914 * @param type The metric type
915 */
916 void srte_candidate_unset_metric(struct srte_candidate *candidate,
917 enum srte_candidate_metric_type type)
918 {
919 struct srte_policy *policy = candidate->policy;
920 char endpoint[ENDPOINT_STR_LENGTH];
921
922 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
923 PATH_POLICY_DEBUG(
924 "SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
925 endpoint, policy->color, candidate->name,
926 srte_candidate_metric_name(type), type);
927 assert((type > 0) && (type <= MAX_METRIC_TYPE));
928 srte_unset_metric(&candidate->metrics[type - 1]);
929 srte_lsp_unset_metric(candidate->lsp, type);
930 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
931 }
932
933 /**
934 * Removes a candidate path metric constraint.
935 *
936 * The changes will not be shown as part of the running configuration.
937 *
938 * @param lsp The LSP from which the metric should be removed
939 * @param type The metric type
940 */
941 void srte_lsp_unset_metric(struct srte_lsp *lsp,
942 enum srte_candidate_metric_type type)
943 {
944 struct srte_candidate *candidate = lsp->candidate;
945 struct srte_policy *policy = candidate->policy;
946 char endpoint[ENDPOINT_STR_LENGTH];
947
948 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
949 PATH_POLICY_DEBUG(
950 "SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
951 endpoint, policy->color, candidate->name,
952 srte_candidate_metric_name(type), type);
953 assert((type > 0) && (type <= MAX_METRIC_TYPE));
954 srte_unset_metric(&lsp->metrics[type - 1]);
955 }
956
957 void srte_unset_metric(struct srte_metric *metric)
958 {
959 UNSET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
960 UNSET_FLAG(metric->flags, F_METRIC_IS_BOUND);
961 UNSET_FLAG(metric->flags, F_METRIC_IS_COMPUTED);
962 metric->value = 0;
963 }
964
965 /**
966 * Sets a candidate path objective function.
967 *
968 * @param candidate The candidate path of which the OF should be changed
969 * @param required If the constraint is required (true) or only desired (false)
970 * @param type The objective function type
971 */
972 void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
973 enum objfun_type type)
974 {
975 struct srte_policy *policy = candidate->policy;
976 char endpoint[ENDPOINT_STR_LENGTH];
977
978 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
979
980 candidate->objfun = type;
981 SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
982 COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
983 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
984 PATH_POLICY_DEBUG(
985 "SR-TE(%s, %u): candidate %s %sobjective function set to %s",
986 endpoint, policy->color, candidate->name,
987 required ? "required " : "", objfun_type_name(type));
988 }
989
990 /**
991 * Removed the objective function constraint from a candidate path.
992 *
993 * @param candidate The candidate path from which the OF should be removed
994 */
995 void srte_candidate_unset_objfun(struct srte_candidate *candidate)
996 {
997 struct srte_policy *policy = candidate->policy;
998 char endpoint[ENDPOINT_STR_LENGTH];
999
1000 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1001
1002 UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
1003 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
1004 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
1005 candidate->objfun = OBJFUN_UNDEFINED;
1006 PATH_POLICY_DEBUG(
1007 "SR-TE(%s, %u): candidate %s objective functions preferences unset",
1008 endpoint, policy->color, candidate->name);
1009 }
1010
1011 static uint32_t filter_type_to_flag(enum affinity_filter_type type)
1012 {
1013 switch (type) {
1014 case AFFINITY_FILTER_EXCLUDE_ANY:
1015 return F_CANDIDATE_HAS_EXCLUDE_ANY;
1016 case AFFINITY_FILTER_INCLUDE_ANY:
1017 return F_CANDIDATE_HAS_INCLUDE_ANY;
1018 case AFFINITY_FILTER_INCLUDE_ALL:
1019 return F_CANDIDATE_HAS_INCLUDE_ALL;
1020 case AFFINITY_FILTER_UNDEFINED:
1021 return 0;
1022 }
1023
1024 assert(!"Reached end of function we should never hit");
1025 }
1026
1027 static const char *filter_type_name(enum affinity_filter_type type)
1028 {
1029 switch (type) {
1030 case AFFINITY_FILTER_EXCLUDE_ANY:
1031 return "exclude-any";
1032 case AFFINITY_FILTER_INCLUDE_ANY:
1033 return "include-any";
1034 case AFFINITY_FILTER_INCLUDE_ALL:
1035 return "include-all";
1036 case AFFINITY_FILTER_UNDEFINED:
1037 return "unknown";
1038 }
1039
1040 assert(!"Reached end of function we should never hit");
1041 }
1042
1043 /**
1044 * Sets a candidate path affinity filter constraint.
1045 *
1046 * @param candidate The candidate path of which the constraint should be changed
1047 * @param type The affinity constraint type to set
1048 * @param filter The bitmask filter of the constraint
1049 */
1050 void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
1051 enum affinity_filter_type type,
1052 uint32_t filter)
1053 {
1054 struct srte_policy *policy = candidate->policy;
1055 char endpoint[ENDPOINT_STR_LENGTH];
1056
1057 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1058
1059 assert(type > AFFINITY_FILTER_UNDEFINED);
1060 assert(type <= MAX_AFFINITY_FILTER_TYPE);
1061 SET_FLAG(candidate->flags, filter_type_to_flag(type));
1062 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
1063 candidate->affinity_filters[type - 1] = filter;
1064 PATH_POLICY_DEBUG(
1065 "SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
1066 endpoint, policy->color, candidate->name,
1067 filter_type_name(type), filter);
1068 }
1069
1070 /**
1071 * Removes a candidate path affinity filter constraint.
1072 *
1073 * @param candidate The candidate path from which the constraint should be
1074 * removed
1075 * @param type The affinity constraint type to remove
1076 */
1077 void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
1078 enum affinity_filter_type type)
1079 {
1080 struct srte_policy *policy = candidate->policy;
1081 char endpoint[ENDPOINT_STR_LENGTH];
1082
1083 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1084
1085 assert(type > AFFINITY_FILTER_UNDEFINED);
1086 assert(type <= MAX_AFFINITY_FILTER_TYPE);
1087 UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
1088 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
1089 candidate->affinity_filters[type - 1] = 0;
1090 PATH_POLICY_DEBUG(
1091 "SR-TE(%s, %u): candidate %s affinity filter %s unset",
1092 endpoint, policy->color, candidate->name,
1093 filter_type_name(type));
1094 }
1095
1096 /**
1097 * Searches for a candidate path of the given policy.
1098 *
1099 * @param policy The policy to search for candidate path
1100 * @param preference The preference of the candidate path you are looking for
1101 * @return The candidate path if found, NULL otherwise
1102 */
1103 struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
1104 uint32_t preference)
1105 {
1106 struct srte_candidate search;
1107
1108 search.preference = preference;
1109 return RB_FIND(srte_candidate_head, &policy->candidate_paths, &search);
1110 }
1111
1112 /**
1113 * Searches for a an entry of a given segment list.
1114 *
1115 * @param segment_list The segment list to search for the entry
1116 * @param index The index of the entry you are looking for
1117 * @return The segment list entry if found, NULL otherwise.
1118 */
1119 struct srte_segment_entry *
1120 srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
1121 {
1122 struct srte_segment_entry search;
1123
1124 search.index = index;
1125 return RB_FIND(srte_segment_entry_head, &segment_list->segments,
1126 &search);
1127 }
1128
1129 /**
1130 * Updates a candidate status.
1131 *
1132 * @param candidate The candidate of which the status should be updated
1133 * @param status The new candidate path status
1134 */
1135 void srte_candidate_status_update(struct srte_candidate *candidate, int status)
1136 {
1137 struct srte_policy *policy = candidate->policy;
1138 char endpoint[ENDPOINT_STR_LENGTH];
1139
1140 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1141 PATH_POLICY_DEBUG("SR-TE(%s, %u): zebra updated status to %d", endpoint,
1142 policy->color, status);
1143 switch (status) {
1144 case ZEBRA_SR_POLICY_DOWN:
1145 switch (policy->status) {
1146 /* If the policy is GOING_UP, and zebra faild
1147 to install it, we wait for zebra to retry */
1148 /* TODO: Add some timeout after which we would
1149 get is back to DOWN and remove the
1150 policy */
1151 case SRTE_POLICY_STATUS_GOING_UP:
1152 case SRTE_POLICY_STATUS_DOWN:
1153 return;
1154 case SRTE_POLICY_STATUS_UNKNOWN:
1155 case SRTE_POLICY_STATUS_UP:
1156 case SRTE_POLICY_STATUS_GOING_DOWN:
1157 policy->status = SRTE_POLICY_STATUS_DOWN;
1158 srte_policy_status_log(policy);
1159 break;
1160 }
1161 break;
1162 case ZEBRA_SR_POLICY_UP:
1163 switch (policy->status) {
1164 case SRTE_POLICY_STATUS_UP:
1165 return;
1166 case SRTE_POLICY_STATUS_UNKNOWN:
1167 case SRTE_POLICY_STATUS_DOWN:
1168 case SRTE_POLICY_STATUS_GOING_DOWN:
1169 case SRTE_POLICY_STATUS_GOING_UP:
1170 policy->status = SRTE_POLICY_STATUS_UP;
1171 srte_policy_status_log(policy);
1172 break;
1173 }
1174 break;
1175 }
1176
1177 trigger_pathd_candidate_updated(candidate);
1178 }
1179
1180 /**
1181 * Flags the segment lists from give originator for removal.
1182 *
1183 * The function srte_apply_changes must be called afterward for
1184 * the segment list to be removed.
1185 *
1186 * @param originator The originator tag of the segment list to be marked
1187 * @param force If the unset should be forced regardless of the originator
1188 */
1189 void srte_candidate_unset_segment_list(const char *originator, bool force)
1190 {
1191 if (originator == NULL) {
1192 zlog_warn(
1193 "Cannot unset segment list because originator is NULL");
1194 return;
1195 }
1196
1197 PATH_POLICY_DEBUG("Unset segment lists for originator %s", originator);
1198
1199 /* Iterate the policies, then iterate each policy's candidate path
1200 * to check the candidate path's segment list originator */
1201 struct srte_policy *policy;
1202 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
1203 PATH_POLICY_DEBUG("Unset segment lists checking policy %s",
1204 policy->name);
1205 struct srte_candidate *candidate;
1206 RB_FOREACH (candidate, srte_candidate_head,
1207 &policy->candidate_paths) {
1208 PATH_POLICY_DEBUG(
1209 "Unset segment lists checking candidate %s",
1210 candidate->name);
1211 if (candidate->lsp == NULL) {
1212 continue;
1213 }
1214
1215 /* The candidate->lsp->segment_list is operational data,
1216 * configured by the PCE. We dont want to modify the
1217 * candidate->segment_list,
1218 * which is configuration data. */
1219 struct srte_segment_list *segment_list =
1220 candidate->lsp->segment_list;
1221 if (segment_list == NULL) {
1222 continue;
1223 }
1224
1225 if (segment_list->protocol_origin
1226 == SRTE_ORIGIN_LOCAL) {
1227 zlog_warn(
1228 "Cannot unset segment list %s because it was created locally",
1229 segment_list->name);
1230 continue;
1231 }
1232
1233 /* In the case of last pce,we force the unset
1234 * because we don't have pce by prefix (TODO) is all
1235 * 'global' */
1236 if (strncmp(segment_list->originator, originator,
1237 sizeof(segment_list->originator))
1238 == 0
1239 || force) {
1240 PATH_POLICY_DEBUG("Unset segment list %s",
1241 segment_list->name);
1242 SET_FLAG(segment_list->flags,
1243 F_SEGMENT_LIST_DELETED);
1244 SET_FLAG(candidate->flags,
1245 F_CANDIDATE_MODIFIED);
1246 candidate->lsp->segment_list = NULL;
1247 }
1248 }
1249 }
1250 }
1251
1252 /**
1253 * Gives a string representation of given protocol origin enum.
1254 *
1255 * @param origin The enum you want a string representation of
1256 * @return The string representation of given enum
1257 */
1258 const char *srte_origin2str(enum srte_protocol_origin origin)
1259 {
1260 switch (origin) {
1261 case SRTE_ORIGIN_PCEP:
1262 return "PCEP";
1263 case SRTE_ORIGIN_BGP:
1264 return "BGP";
1265 case SRTE_ORIGIN_LOCAL:
1266 return "Local";
1267 case SRTE_ORIGIN_UNDEFINED:
1268 return "Unknown";
1269 }
1270
1271 assert(!"Reached end of function we should never hit");
1272 }
1273
1274 void path_policy_show_debugging(struct vty *vty)
1275 {
1276 if (DEBUG_FLAGS_CHECK(&path_policy_debug, PATH_POLICY_DEBUG_BASIC))
1277 vty_out(vty, " Path policy debugging is on\n");
1278 }
1279
1280 void pathd_shutdown(void)
1281 {
1282 path_ted_teardown();
1283 srte_clean_zebra();
1284 frr_fini();
1285 }
1286
1287 void trigger_pathd_candidate_created(struct srte_candidate *candidate)
1288 {
1289 /* The hook is called asynchronously to let the PCEP module
1290 time to send a response to the PCE before receiving any updates from
1291 pathd. In addition, a minimum amount of time need to pass before
1292 the hook is called to prevent the hook to be called multiple times
1293 from changing the candidate by hand with the console */
1294 if (candidate->hook_timer != NULL)
1295 return;
1296 thread_add_timer(master, trigger_pathd_candidate_created_timer,
1297 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
1298 }
1299
1300 void trigger_pathd_candidate_created_timer(struct thread *thread)
1301 {
1302 struct srte_candidate *candidate = THREAD_ARG(thread);
1303 candidate->hook_timer = NULL;
1304 hook_call(pathd_candidate_created, candidate);
1305 }
1306
1307 void trigger_pathd_candidate_updated(struct srte_candidate *candidate)
1308 {
1309 /* The hook is called asynchronously to let the PCEP module
1310 time to send a response to the PCE before receiving any updates from
1311 pathd. In addition, a minimum amount of time need to pass before
1312 the hook is called to prevent the hook to be called multiple times
1313 from changing the candidate by hand with the console */
1314 if (candidate->hook_timer != NULL)
1315 return;
1316 thread_add_timer(master, trigger_pathd_candidate_updated_timer,
1317 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
1318 }
1319
1320 void trigger_pathd_candidate_updated_timer(struct thread *thread)
1321 {
1322 struct srte_candidate *candidate = THREAD_ARG(thread);
1323 candidate->hook_timer = NULL;
1324 hook_call(pathd_candidate_updated, candidate);
1325 }
1326
1327 void trigger_pathd_candidate_removed(struct srte_candidate *candidate)
1328 {
1329 /* The hook needs to be call synchronously, otherwise the candidate
1330 path will be already deleted when the handler is called */
1331 if (candidate->hook_timer != NULL) {
1332 thread_cancel(&candidate->hook_timer);
1333 candidate->hook_timer = NULL;
1334 }
1335 hook_call(pathd_candidate_removed, candidate);
1336 }
1337
1338 const char *srte_candidate_metric_name(enum srte_candidate_metric_type type)
1339 {
1340 switch (type) {
1341 case SRTE_CANDIDATE_METRIC_TYPE_IGP:
1342 return "IGP";
1343 case SRTE_CANDIDATE_METRIC_TYPE_TE:
1344 return "TE";
1345 case SRTE_CANDIDATE_METRIC_TYPE_HC:
1346 return "HC";
1347 case SRTE_CANDIDATE_METRIC_TYPE_ABC:
1348 return "ABC";
1349 case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
1350 return "LMLL";
1351 case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
1352 return "CIGP";
1353 case SRTE_CANDIDATE_METRIC_TYPE_CTE:
1354 return "CTE";
1355 case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
1356 return "PIGP";
1357 case SRTE_CANDIDATE_METRIC_TYPE_PTE:
1358 return "PTE";
1359 case SRTE_CANDIDATE_METRIC_TYPE_PHC:
1360 return "PHC";
1361 case SRTE_CANDIDATE_METRIC_TYPE_MSD:
1362 return "MSD";
1363 case SRTE_CANDIDATE_METRIC_TYPE_PD:
1364 return "PD";
1365 case SRTE_CANDIDATE_METRIC_TYPE_PDV:
1366 return "PDV";
1367 case SRTE_CANDIDATE_METRIC_TYPE_PL:
1368 return "PL";
1369 case SRTE_CANDIDATE_METRIC_TYPE_PPD:
1370 return "PPD";
1371 case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
1372 return "PPDV";
1373 case SRTE_CANDIDATE_METRIC_TYPE_PPL:
1374 return "PPL";
1375 case SRTE_CANDIDATE_METRIC_TYPE_NAP:
1376 return "NAP";
1377 case SRTE_CANDIDATE_METRIC_TYPE_NLP:
1378 return "NLP";
1379 case SRTE_CANDIDATE_METRIC_TYPE_DC:
1380 return "DC";
1381 case SRTE_CANDIDATE_METRIC_TYPE_BNC:
1382 return "BNC";
1383 default:
1384 return "UNKNOWN";
1385 }
1386 }
1387
1388 int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry,
1389 struct prefix *prefix_cli, uint32_t algo)
1390 {
1391 int32_t status = 0;
1392 uint32_t ted_sid = MPLS_LABEL_NONE;
1393
1394 if (!entry || !prefix_cli)
1395 return 0;
1396
1397 if (!path_ted_is_initialized())
1398 return 0;
1399
1400 ted_sid = path_ted_query_type_c(prefix_cli, algo);
1401 if (ted_sid == MPLS_LABEL_NONE) {
1402 zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)",
1403 __func__, ted_sid);
1404 } else {
1405 PATH_TED_DEBUG(
1406 "%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
1407 __func__, ted_sid);
1408 }
1409 if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
1410 entry->sid_value)) {
1411 status = PATH_SID_ERROR;
1412 } else
1413 srte_segment_set_local_modification(entry->segment_list, entry,
1414 ted_sid);
1415 return status;
1416 }
1417
1418 int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry,
1419 struct prefix *prefix_cli,
1420 uint32_t local_iface)
1421 {
1422 int32_t status = 0;
1423 uint32_t ted_sid = MPLS_LABEL_NONE;
1424
1425 if (!entry || !prefix_cli)
1426 return 0;
1427
1428 if (!path_ted_is_initialized())
1429 return 0;
1430
1431 ted_sid = path_ted_query_type_e(prefix_cli, local_iface);
1432 if (ted_sid == MPLS_LABEL_NONE) {
1433 zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)",
1434 __func__, ted_sid);
1435 } else {
1436 PATH_TED_DEBUG(
1437 "%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
1438 __func__, ted_sid);
1439 }
1440 if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
1441 entry->sid_value)) {
1442 status = PATH_SID_ERROR;
1443 } else
1444 srte_segment_set_local_modification(entry->segment_list, entry,
1445 ted_sid);
1446 return status;
1447 }
1448
1449 int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry,
1450 struct ipaddr *local, struct ipaddr *remote)
1451 {
1452 int32_t status = 0;
1453 uint32_t ted_sid = MPLS_LABEL_NONE;
1454
1455 if (!entry || !local || !remote)
1456 return 0;
1457
1458 if (!path_ted_is_initialized())
1459 return status;
1460
1461 ted_sid = path_ted_query_type_f(local, remote);
1462 if (ted_sid == MPLS_LABEL_NONE) {
1463 zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__,
1464 ted_sid);
1465 } else {
1466 PATH_TED_DEBUG("%s:SL: Success query F : ted-sid (%d)",
1467 __func__, ted_sid);
1468 }
1469 if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
1470 entry->sid_value)) {
1471 status = PATH_SID_ERROR;
1472 } else
1473 srte_segment_set_local_modification(entry->segment_list, entry,
1474 ted_sid);
1475 return status;
1476 }