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