]> git.proxmox.com Git - mirror_frr.git/blob - pathd/pathd.c
pathd: add a zebra stop handler
[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 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 /**
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 path_zebra_stop();
515 }
516
517 /**
518 * Apply changes defined by setting the policies, candidate paths
519 * and segment lists modification flags NEW, MODIFIED and DELETED.
520 *
521 * This allows the northbound code to delay all the side effects of adding
522 * modifying and deleting them to the end.
523 *
524 * Example of marking an object as modified:
525 * `SET_FLAG(obj->flags, F_XXX_MODIFIED)`
526 */
527 void srte_apply_changes(void)
528 {
529 struct srte_policy *policy, *safe_pol;
530 struct srte_segment_list *segment_list, *safe_sl;
531
532 RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
533 if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
534 srte_policy_del(policy);
535 continue;
536 }
537 srte_policy_apply_changes(policy);
538 UNSET_FLAG(policy->flags, F_POLICY_NEW);
539 UNSET_FLAG(policy->flags, F_POLICY_MODIFIED);
540 }
541
542 RB_FOREACH_SAFE (segment_list, srte_segment_list_head,
543 &srte_segment_lists, safe_sl) {
544 if (CHECK_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED)) {
545 srte_segment_list_del(segment_list);
546 continue;
547 }
548 UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
549 UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
550 }
551 }
552
553 /**
554 * Apply changes defined by setting the given policy and its candidate paths
555 * modification flags NEW, MODIFIED and DELETED.
556 *
557 * In moste cases `void srte_apply_changes(void)` should be used instead,
558 * this function will not handle the changes of segment lists used by the
559 * policy.
560 *
561 * @param policy The policy changes has to be applied to.
562 */
563 void srte_policy_apply_changes(struct srte_policy *policy)
564 {
565 struct srte_candidate *candidate, *safe;
566 struct srte_candidate *old_best_candidate;
567 struct srte_candidate *new_best_candidate;
568 char endpoint[46];
569
570 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
571
572 /* Get old and new best candidate path. */
573 old_best_candidate = policy->best_candidate;
574 new_best_candidate = srte_policy_best_candidate(policy);
575
576 if (new_best_candidate != old_best_candidate) {
577 /* TODO: add debug guard. */
578 zlog_debug(
579 "SR-TE(%s, %u): best candidate changed from %s to %s",
580 endpoint, policy->color,
581 old_best_candidate ? old_best_candidate->name : "none",
582 new_best_candidate ? new_best_candidate->name : "none");
583
584 if (old_best_candidate) {
585 policy->best_candidate = NULL;
586 UNSET_FLAG(old_best_candidate->flags, F_CANDIDATE_BEST);
587 SET_FLAG(old_best_candidate->flags,
588 F_CANDIDATE_MODIFIED);
589
590 /*
591 * Rely on replace semantics if there's a new best
592 * candidate.
593 */
594 if (!new_best_candidate)
595 path_zebra_delete_sr_policy(policy);
596 }
597 if (new_best_candidate) {
598 policy->best_candidate = new_best_candidate;
599 SET_FLAG(new_best_candidate->flags, F_CANDIDATE_BEST);
600 SET_FLAG(new_best_candidate->flags,
601 F_CANDIDATE_MODIFIED);
602
603 path_zebra_add_sr_policy(
604 policy, new_best_candidate->lsp->segment_list);
605 }
606 } else if (new_best_candidate) {
607 /* The best candidate path did not change, but some of its
608 * attributes or its segment list may have changed.
609 */
610
611 bool candidate_changed = CHECK_FLAG(new_best_candidate->flags,
612 F_CANDIDATE_MODIFIED);
613 bool segment_list_changed =
614 new_best_candidate->lsp->segment_list
615 && CHECK_FLAG(
616 new_best_candidate->lsp->segment_list->flags,
617 F_SEGMENT_LIST_MODIFIED);
618
619 if (candidate_changed || segment_list_changed) {
620 /* TODO: add debug guard. */
621 zlog_debug("SR-TE(%s, %u): best candidate %s changed",
622 endpoint, policy->color,
623 new_best_candidate->name);
624
625 path_zebra_add_sr_policy(
626 policy, new_best_candidate->lsp->segment_list);
627 }
628 }
629
630 RB_FOREACH_SAFE (candidate, srte_candidate_head,
631 &policy->candidate_paths, safe) {
632 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)) {
633 trigger_pathd_candidate_removed(candidate);
634 srte_candidate_del(candidate);
635 continue;
636 } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_NEW)) {
637 trigger_pathd_candidate_created(candidate);
638 } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_MODIFIED)) {
639 trigger_pathd_candidate_updated(candidate);
640 } else if (candidate->lsp->segment_list
641 && CHECK_FLAG(candidate->lsp->segment_list->flags,
642 F_SEGMENT_LIST_MODIFIED)) {
643 trigger_pathd_candidate_updated(candidate);
644 }
645
646 UNSET_FLAG(candidate->flags, F_CANDIDATE_NEW);
647 UNSET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
648 }
649 }
650
651 /**
652 * Adds a candidate path to a policy.
653 *
654 * @param policy The policy the candidate path should be added to
655 * @param preference The preference of the candidate path to be added
656 * @return The added candidate path
657 */
658 struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
659 uint32_t preference,
660 enum srte_protocol_origin origin,
661 const char *originator)
662 {
663 struct srte_candidate *candidate;
664 struct srte_lsp *lsp;
665
666 candidate = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*candidate));
667 lsp = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*lsp));
668
669 candidate->preference = preference;
670 candidate->policy = policy;
671 candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
672 candidate->discriminator = frr_weak_random();
673 candidate->protocol_origin = origin;
674 if (originator != NULL) {
675 strlcpy(candidate->originator, originator,
676 sizeof(candidate->originator));
677 lsp->protocol_origin = origin;
678 }
679
680 if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
681 || candidate->protocol_origin == SRTE_ORIGIN_BGP) {
682 candidate->type = SRTE_CANDIDATE_TYPE_DYNAMIC;
683 }
684 lsp->candidate = candidate;
685 candidate->lsp = lsp;
686
687 RB_INSERT(srte_candidate_head, &policy->candidate_paths, candidate);
688
689 return candidate;
690 }
691
692 /**
693 * Deletes a candidate.
694 *
695 * The corresponding LSP will be removed alongside the candidate path.
696 * The given candidate will be freed and shouldn't be used anymore after the
697 * calling this function.
698 *
699 * @param candidate The candidate path to delete
700 */
701 void srte_candidate_del(struct srte_candidate *candidate)
702 {
703 struct srte_policy *srte_policy = candidate->policy;
704
705 RB_REMOVE(srte_candidate_head, &srte_policy->candidate_paths,
706 candidate);
707
708 XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp);
709 XFREE(MTYPE_PATH_SR_CANDIDATE, candidate);
710 }
711
712 /**
713 * Sets the bandwidth constraint of given candidate path.
714 *
715 * The corresponding LSP will be changed too.
716 *
717 * @param candidate The candidate path of which the bandwidth should be changed
718 * @param bandwidth The Bandwidth constraint to set to the candidate path
719 * @param required If the constraint is required (true) or only desired (false)
720 */
721 void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
722 float bandwidth, bool required)
723 {
724 struct srte_policy *policy = candidate->policy;
725 char endpoint[46];
726
727 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
728 zlog_debug(
729 "SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
730 endpoint, policy->color, candidate->name,
731 required ? "required " : "", bandwidth);
732 SET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
733 COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
734 candidate->bandwidth = bandwidth;
735
736 srte_lsp_set_bandwidth(candidate->lsp, bandwidth, required);
737 }
738
739 /**
740 * Sets the bandwidth constraint of the given LSP.
741 *
742 * The changes will not be shown as part of the running configuration.
743 *
744 * @param lsp The lsp of which the bandwidth should be changed
745 * @param bandwidth The Bandwidth constraint to set to the candidate path
746 * @param required If the constraint is required (true) or only desired (false)
747 */
748 void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
749 bool required)
750 {
751 struct srte_candidate *candidate = lsp->candidate;
752 struct srte_policy *policy = candidate->policy;
753 char endpoint[46];
754 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
755 zlog_debug("SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
756 endpoint, policy->color, candidate->name,
757 required ? "required" : "", bandwidth);
758 SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
759 COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
760 lsp->bandwidth = bandwidth;
761 }
762
763 /**
764 * Remove a candidate path bandwidth constraint.
765 *
766 * The corresponding LSP will be changed too.
767 *
768 * @param candidate The candidate path of which the bandwidth should be removed
769 */
770 void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
771 {
772 struct srte_policy *policy = candidate->policy;
773 char endpoint[46];
774 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
775 zlog_debug("SR-TE(%s, %u): candidate %s config bandwidth unset",
776 endpoint, policy->color, candidate->name);
777 UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
778 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
779 candidate->bandwidth = 0;
780 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
781 srte_lsp_unset_bandwidth(candidate->lsp);
782 }
783
784 /**
785 * Remove an LSP bandwidth constraint.
786 *
787 * The changes will not be shown as part of the running configuration.
788 *
789 * @param lsp The lsp of which the bandwidth should be changed
790 */
791 void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
792 {
793 struct srte_candidate *candidate = lsp->candidate;
794 struct srte_policy *policy = candidate->policy;
795 char endpoint[46];
796 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
797 zlog_debug("SR-TE(%s, %u): candidate %s lsp bandwidth unset", endpoint,
798 policy->color, candidate->name);
799 UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
800 UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
801 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
802 lsp->bandwidth = 0;
803 }
804
805 /**
806 * Sets a candidate path metric constraint.
807 *
808 * The corresponding LSP will be changed too.
809 *
810 * @param candidate The candidate path of which the metric should be changed
811 * @param type The metric type
812 * @param value The metric value
813 * @param required If the constraint is required (true) or only desired (false)
814 * @param is_bound If the metric is an indicative value or a strict upper bound
815 * @param is_computed If the metric was computed or configured
816 */
817 void srte_candidate_set_metric(struct srte_candidate *candidate,
818 enum srte_candidate_metric_type type,
819 float value, bool required, bool is_bound,
820 bool is_computed)
821 {
822 struct srte_policy *policy = candidate->policy;
823 char endpoint[46];
824 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
825 zlog_debug(
826 "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
827 endpoint, policy->color, candidate->name,
828 required ? "required " : "", srte_candidate_metric_name(type),
829 type, value, is_bound ? "true" : "false",
830 is_computed ? "true" : "false");
831 assert((type > 0) && (type <= MAX_METRIC_TYPE));
832 srte_set_metric(&candidate->metrics[type - 1], value, required,
833 is_bound, is_computed);
834 srte_lsp_set_metric(candidate->lsp, type, value, required, is_bound,
835 is_computed);
836 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
837 }
838
839 /**
840 * Sets an LSP metric constraint.
841 *
842 * The changes will not be shown as part of the running configuration.
843 *
844 * @param lsp The LSP of which the metric should be changed
845 * @param type The metric type
846 * @param value The metric value
847 * @param required If the constraint is required (true) or only desired (false)
848 * @param is_bound If the metric is an indicative value or a strict upper bound
849 * @param is_computed If the metric was computed or configured
850 */
851 void srte_lsp_set_metric(struct srte_lsp *lsp,
852 enum srte_candidate_metric_type type, float value,
853 bool required, bool is_bound, bool is_computed)
854 {
855 struct srte_candidate *candidate = lsp->candidate;
856 struct srte_policy *policy = candidate->policy;
857 char endpoint[46];
858 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
859 zlog_debug(
860 "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
861 endpoint, policy->color, candidate->name,
862 required ? "required " : "", srte_candidate_metric_name(type),
863 type, value, is_bound ? "true" : "false",
864 is_computed ? "true" : "false");
865 assert((type > 0) && (type <= MAX_METRIC_TYPE));
866 srte_set_metric(&lsp->metrics[type - 1], value, required, is_bound,
867 is_computed);
868 }
869
870 void srte_set_metric(struct srte_metric *metric, float value, bool required,
871 bool is_bound, bool is_computed)
872 {
873 SET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
874 COND_FLAG(metric->flags, F_METRIC_IS_REQUIRED, required);
875 COND_FLAG(metric->flags, F_METRIC_IS_BOUND, is_bound);
876 COND_FLAG(metric->flags, F_METRIC_IS_COMPUTED, is_computed);
877 metric->value = value;
878 }
879
880 /**
881 * Removes a candidate path metric constraint.
882 *
883 * The corresponding LSP will be changed too.
884 *
885 * @param candidate The candidate path from which the metric should be removed
886 * @param type The metric type
887 */
888 void srte_candidate_unset_metric(struct srte_candidate *candidate,
889 enum srte_candidate_metric_type type)
890 {
891 struct srte_policy *policy = candidate->policy;
892 char endpoint[46];
893 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
894 zlog_debug("SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
895 endpoint, policy->color, candidate->name,
896 srte_candidate_metric_name(type), type);
897 assert((type > 0) && (type <= MAX_METRIC_TYPE));
898 srte_unset_metric(&candidate->metrics[type - 1]);
899 srte_lsp_unset_metric(candidate->lsp, type);
900 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
901 }
902
903 /**
904 * Removes a candidate path metric constraint.
905 *
906 * The changes will not be shown as part of the running configuration.
907 *
908 * @param lsp The LSP from which the metric should be removed
909 * @param type The metric type
910 */
911 void srte_lsp_unset_metric(struct srte_lsp *lsp,
912 enum srte_candidate_metric_type type)
913 {
914 struct srte_candidate *candidate = lsp->candidate;
915 struct srte_policy *policy = candidate->policy;
916 char endpoint[46];
917 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
918 zlog_debug("SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
919 endpoint, policy->color, candidate->name,
920 srte_candidate_metric_name(type), type);
921 assert((type > 0) && (type <= MAX_METRIC_TYPE));
922 srte_unset_metric(&lsp->metrics[type - 1]);
923 }
924
925 void srte_unset_metric(struct srte_metric *metric)
926 {
927 UNSET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
928 UNSET_FLAG(metric->flags, F_METRIC_IS_BOUND);
929 UNSET_FLAG(metric->flags, F_METRIC_IS_COMPUTED);
930 metric->value = 0;
931 }
932
933 /**
934 * Sets a candidate path objective function.
935 *
936 * @param candidate The candidate path of which the OF should be changed
937 * @param required If the constraint is required (true) or only desired (false)
938 * @param type The objective function type
939 */
940 void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
941 enum objfun_type type)
942 {
943 struct srte_policy *policy = candidate->policy;
944 char endpoint[46];
945 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
946
947 candidate->objfun = type;
948 SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
949 COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
950 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
951 zlog_debug("SR-TE(%s, %u): candidate %s %sobjective function set to %s",
952 endpoint, policy->color, candidate->name,
953 required ? "required " : "", objfun_type_name(type));
954 }
955
956 /**
957 * Removed the objective function constraint from a candidate path.
958 *
959 * @param candidate The candidate path from which the OF should be removed
960 */
961 void srte_candidate_unset_objfun(struct srte_candidate *candidate)
962 {
963 struct srte_policy *policy = candidate->policy;
964 char endpoint[46];
965 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
966
967 UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
968 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
969 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
970 candidate->objfun = OBJFUN_UNDEFINED;
971 zlog_debug(
972 "SR-TE(%s, %u): candidate %s objective functions preferences unset",
973 endpoint, policy->color, candidate->name);
974 }
975
976 static uint32_t filter_type_to_flag(enum affinity_filter_type type)
977 {
978 switch (type) {
979 case AFFINITY_FILTER_EXCLUDE_ANY:
980 return F_CANDIDATE_HAS_EXCLUDE_ANY;
981 case AFFINITY_FILTER_INCLUDE_ANY:
982 return F_CANDIDATE_HAS_INCLUDE_ANY;
983 case AFFINITY_FILTER_INCLUDE_ALL:
984 return F_CANDIDATE_HAS_INCLUDE_ALL;
985 default:
986 return 0;
987 }
988 }
989
990 static const char *filter_type_name(enum affinity_filter_type type)
991 {
992 switch (type) {
993 case AFFINITY_FILTER_EXCLUDE_ANY:
994 return "exclude-any";
995 case AFFINITY_FILTER_INCLUDE_ANY:
996 return "include-any";
997 case AFFINITY_FILTER_INCLUDE_ALL:
998 return "include-all";
999 default:
1000 return "unknown";
1001 }
1002 }
1003
1004 /**
1005 * Sets a candidate path affinity filter constraint.
1006 *
1007 * @param candidate The candidate path of which the constraint should be changed
1008 * @param type The affinity constraint type to set
1009 * @param filter The bitmask filter of the constraint
1010 */
1011 void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
1012 enum affinity_filter_type type,
1013 uint32_t filter)
1014 {
1015 struct srte_policy *policy = candidate->policy;
1016 char endpoint[46];
1017 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1018
1019 assert(type > AFFINITY_FILTER_UNDEFINED);
1020 assert(type <= MAX_AFFINITY_FILTER_TYPE);
1021 SET_FLAG(candidate->flags, filter_type_to_flag(type));
1022 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
1023 candidate->affinity_filters[type - 1] = filter;
1024 zlog_debug(
1025 "SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
1026 endpoint, policy->color, candidate->name,
1027 filter_type_name(type), filter);
1028 }
1029
1030 /**
1031 * Removes a candidate path affinity filter constraint.
1032 *
1033 * @param candidate The candidate path from which the constraint should be
1034 * removed
1035 * @param type The affinity constraint type to remove
1036 */
1037 void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
1038 enum affinity_filter_type type)
1039 {
1040 struct srte_policy *policy = candidate->policy;
1041 char endpoint[46];
1042 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1043
1044 assert(type > AFFINITY_FILTER_UNDEFINED);
1045 assert(type <= MAX_AFFINITY_FILTER_TYPE);
1046 UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
1047 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
1048 candidate->affinity_filters[type - 1] = 0;
1049 zlog_debug("SR-TE(%s, %u): candidate %s affinity filter %s unset",
1050 endpoint, policy->color, candidate->name,
1051 filter_type_name(type));
1052 }
1053
1054 /**
1055 * Searches for a candidate path of the given policy.
1056 *
1057 * @param policy The policy to search for candidate path
1058 * @param preference The preference of the candidate path you are looking for
1059 * @return The candidate path if found, NULL otherwise
1060 */
1061 struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
1062 uint32_t preference)
1063 {
1064 struct srte_candidate search;
1065
1066 search.preference = preference;
1067 return RB_FIND(srte_candidate_head, &policy->candidate_paths, &search);
1068 }
1069
1070 /**
1071 * Searches for a an entry of a given segment list.
1072 *
1073 * @param segment_list The segment list to search for the entry
1074 * @param index The index of the entry you are looking for
1075 * @return The segment list entry if found, NULL otherwise.
1076 */
1077 struct srte_segment_entry *
1078 srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
1079 {
1080 struct srte_segment_entry search;
1081
1082 search.index = index;
1083 return RB_FIND(srte_segment_entry_head, &segment_list->segments,
1084 &search);
1085 }
1086
1087 /**
1088 * Updates a candidate status.
1089 *
1090 * @param candidate The candidate of which the status should be updated
1091 * @param status The new candidate path status
1092 */
1093 void srte_candidate_status_update(struct srte_candidate *candidate, int status)
1094 {
1095 struct srte_policy *policy = candidate->policy;
1096 char endpoint[46];
1097 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
1098 zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
1099 policy->color, status);
1100 switch (status) {
1101 case ZEBRA_SR_POLICY_DOWN:
1102 switch (policy->status) {
1103 /* If the policy is GOING_UP, and zebra faild
1104 to install it, we wait for zebra to retry */
1105 /* TODO: Add some timeout after which we would
1106 get is back to DOWN and remove the
1107 policy */
1108 case SRTE_POLICY_STATUS_GOING_UP:
1109 case SRTE_POLICY_STATUS_DOWN:
1110 return;
1111 default:
1112 zlog_debug("SR-TE(%s, %u): policy is DOWN", endpoint,
1113 policy->color);
1114 policy->status = SRTE_POLICY_STATUS_DOWN;
1115 break;
1116 }
1117 break;
1118 case ZEBRA_SR_POLICY_UP:
1119 switch (policy->status) {
1120 case SRTE_POLICY_STATUS_UP:
1121 return;
1122 default:
1123 zlog_debug("SR-TE(%s, %u): policy is UP", endpoint,
1124 policy->color);
1125 policy->status = SRTE_POLICY_STATUS_UP;
1126 break;
1127 }
1128 break;
1129 }
1130
1131 trigger_pathd_candidate_updated(candidate);
1132 }
1133
1134 /**
1135 * Flags the segment lists from give originator for removal.
1136 *
1137 * The function srte_apply_changes must be called afterward for
1138 * the segment list to be removed.
1139 *
1140 * @param originator The originator tag of the segment list to be marked
1141 * @param force If the unset should be forced regardless of the originator
1142 */
1143 void srte_candidate_unset_segment_list(const char *originator, bool force)
1144 {
1145 if (originator == NULL) {
1146 zlog_warn(
1147 "Cannot unset segment list because originator is NULL");
1148 return;
1149 }
1150
1151 zlog_debug("Unset segment lists for originator %s", originator);
1152
1153 /* Iterate the policies, then iterate each policy's candidate path
1154 * to check the candidate path's segment list originator */
1155 struct srte_policy *policy;
1156 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
1157 zlog_debug("Unset segment lists checking policy %s",
1158 policy->name);
1159 struct srte_candidate *candidate;
1160 RB_FOREACH (candidate, srte_candidate_head,
1161 &policy->candidate_paths) {
1162 zlog_debug("Unset segment lists checking candidate %s",
1163 candidate->name);
1164 if (candidate->lsp == NULL) {
1165 continue;
1166 }
1167
1168 /* The candidate->lsp->segment_list is operational data,
1169 * configured by the PCE. We dont want to modify the
1170 * candidate->segment_list,
1171 * which is configuration data. */
1172 struct srte_segment_list *segment_list =
1173 candidate->lsp->segment_list;
1174 if (segment_list == NULL) {
1175 continue;
1176 }
1177
1178 if (segment_list->protocol_origin
1179 == SRTE_ORIGIN_LOCAL) {
1180 zlog_warn(
1181 "Cannot unset segment list %s because it was created locally",
1182 segment_list->name);
1183 continue;
1184 }
1185
1186 /* In the case of last pce,we force the unset
1187 * because we don't have pce by prefix (TODO) is all
1188 * 'global' */
1189 if (strncmp(segment_list->originator, originator,
1190 sizeof(segment_list->originator))
1191 == 0
1192 || force) {
1193 zlog_debug("Unset segment list %s",
1194 segment_list->name);
1195 SET_FLAG(segment_list->flags,
1196 F_SEGMENT_LIST_DELETED);
1197 SET_FLAG(candidate->flags,
1198 F_CANDIDATE_MODIFIED);
1199 candidate->lsp->segment_list = NULL;
1200 }
1201 }
1202 }
1203 }
1204
1205 /**
1206 * Gives a string representation of given protocol origin enum.
1207 *
1208 * @param origin The enum you want a string representation of
1209 * @return The string representation of given enum
1210 */
1211 const char *srte_origin2str(enum srte_protocol_origin origin)
1212 {
1213 switch (origin) {
1214 case SRTE_ORIGIN_PCEP:
1215 return "PCEP";
1216 case SRTE_ORIGIN_BGP:
1217 return "BGP";
1218 case SRTE_ORIGIN_LOCAL:
1219 return "Local";
1220 default:
1221 return "Unknown";
1222 }
1223 }
1224
1225 void pathd_shutdown(void)
1226 {
1227 path_ted_teardown();
1228 srte_clean_zebra();
1229 frr_fini();
1230 }
1231
1232 void trigger_pathd_candidate_created(struct srte_candidate *candidate)
1233 {
1234 /* The hook is called asynchronously to let the PCEP module
1235 time to send a response to the PCE before receiving any updates from
1236 pathd. In addition, a minimum amount of time need to pass before
1237 the hook is called to prevent the hook to be called multiple times
1238 from changing the candidate by hand with the console */
1239 if (candidate->hook_timer != NULL)
1240 return;
1241 thread_add_timer(master, trigger_pathd_candidate_created_timer,
1242 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
1243 }
1244
1245 void trigger_pathd_candidate_created_timer(struct thread *thread)
1246 {
1247 struct srte_candidate *candidate = THREAD_ARG(thread);
1248 candidate->hook_timer = NULL;
1249 hook_call(pathd_candidate_created, candidate);
1250 }
1251
1252 void trigger_pathd_candidate_updated(struct srte_candidate *candidate)
1253 {
1254 /* The hook is called asynchronously to let the PCEP module
1255 time to send a response to the PCE before receiving any updates from
1256 pathd. In addition, a minimum amount of time need to pass before
1257 the hook is called to prevent the hook to be called multiple times
1258 from changing the candidate by hand with the console */
1259 if (candidate->hook_timer != NULL)
1260 return;
1261 thread_add_timer(master, trigger_pathd_candidate_updated_timer,
1262 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
1263 }
1264
1265 void trigger_pathd_candidate_updated_timer(struct thread *thread)
1266 {
1267 struct srte_candidate *candidate = THREAD_ARG(thread);
1268 candidate->hook_timer = NULL;
1269 hook_call(pathd_candidate_updated, candidate);
1270 }
1271
1272 void trigger_pathd_candidate_removed(struct srte_candidate *candidate)
1273 {
1274 /* The hook needs to be call synchronously, otherwise the candidate
1275 path will be already deleted when the handler is called */
1276 if (candidate->hook_timer != NULL) {
1277 thread_cancel(&candidate->hook_timer);
1278 candidate->hook_timer = NULL;
1279 }
1280 hook_call(pathd_candidate_removed, candidate);
1281 }
1282
1283 const char *srte_candidate_metric_name(enum srte_candidate_metric_type type)
1284 {
1285 switch (type) {
1286 case SRTE_CANDIDATE_METRIC_TYPE_IGP:
1287 return "IGP";
1288 case SRTE_CANDIDATE_METRIC_TYPE_TE:
1289 return "TE";
1290 case SRTE_CANDIDATE_METRIC_TYPE_HC:
1291 return "HC";
1292 case SRTE_CANDIDATE_METRIC_TYPE_ABC:
1293 return "ABC";
1294 case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
1295 return "LMLL";
1296 case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
1297 return "CIGP";
1298 case SRTE_CANDIDATE_METRIC_TYPE_CTE:
1299 return "CTE";
1300 case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
1301 return "PIGP";
1302 case SRTE_CANDIDATE_METRIC_TYPE_PTE:
1303 return "PTE";
1304 case SRTE_CANDIDATE_METRIC_TYPE_PHC:
1305 return "PHC";
1306 case SRTE_CANDIDATE_METRIC_TYPE_MSD:
1307 return "MSD";
1308 case SRTE_CANDIDATE_METRIC_TYPE_PD:
1309 return "PD";
1310 case SRTE_CANDIDATE_METRIC_TYPE_PDV:
1311 return "PDV";
1312 case SRTE_CANDIDATE_METRIC_TYPE_PL:
1313 return "PL";
1314 case SRTE_CANDIDATE_METRIC_TYPE_PPD:
1315 return "PPD";
1316 case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
1317 return "PPDV";
1318 case SRTE_CANDIDATE_METRIC_TYPE_PPL:
1319 return "PPL";
1320 case SRTE_CANDIDATE_METRIC_TYPE_NAP:
1321 return "NAP";
1322 case SRTE_CANDIDATE_METRIC_TYPE_NLP:
1323 return "NLP";
1324 case SRTE_CANDIDATE_METRIC_TYPE_DC:
1325 return "DC";
1326 case SRTE_CANDIDATE_METRIC_TYPE_BNC:
1327 return "BNC";
1328 default:
1329 return "UNKNOWN";
1330 }
1331 }
1332
1333 int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry,
1334 struct prefix *prefix_cli, uint32_t algo)
1335 {
1336 int32_t status = 0;
1337 uint32_t ted_sid = MPLS_LABEL_NONE;
1338
1339 if (!entry || !prefix_cli)
1340 return 0;
1341
1342 if (!path_ted_is_initialized())
1343 return 0;
1344
1345 ted_sid = path_ted_query_type_c(prefix_cli, algo);
1346 if (ted_sid == MPLS_LABEL_NONE) {
1347 zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)",
1348 __func__, ted_sid);
1349 } else {
1350 zlog_debug("%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
1351 __func__, ted_sid);
1352 }
1353 if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
1354 entry->sid_value)) {
1355 status = PATH_SID_ERROR;
1356 } else
1357 srte_segment_set_local_modification(entry->segment_list, entry,
1358 ted_sid);
1359 return status;
1360 }
1361
1362 int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry,
1363 struct prefix *prefix_cli,
1364 uint32_t local_iface)
1365 {
1366 int32_t status = 0;
1367 uint32_t ted_sid = MPLS_LABEL_NONE;
1368
1369 if (!entry || !prefix_cli)
1370 return 0;
1371
1372 if (!path_ted_is_initialized())
1373 return 0;
1374
1375 ted_sid = path_ted_query_type_e(prefix_cli, local_iface);
1376 if (ted_sid == MPLS_LABEL_NONE) {
1377 zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)",
1378 __func__, ted_sid);
1379 } else {
1380 zlog_debug("%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
1381 __func__, ted_sid);
1382 }
1383 if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
1384 entry->sid_value)) {
1385 status = PATH_SID_ERROR;
1386 } else
1387 srte_segment_set_local_modification(entry->segment_list, entry,
1388 ted_sid);
1389 return status;
1390 }
1391
1392 int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry,
1393 struct ipaddr *local, struct ipaddr *remote)
1394 {
1395 int32_t status = 0;
1396 uint32_t ted_sid = MPLS_LABEL_NONE;
1397
1398 if (!entry || !local || !remote)
1399 return 0;
1400
1401 if (!path_ted_is_initialized())
1402 return status;
1403
1404 ted_sid = path_ted_query_type_f(local, remote);
1405 if (ted_sid == MPLS_LABEL_NONE) {
1406 zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__,
1407 ted_sid);
1408 } else {
1409 zlog_debug("%s:SL: Success query F : ted-sid (%d)", __func__,
1410 ted_sid);
1411 }
1412 if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
1413 entry->sid_value)) {
1414 status = PATH_SID_ERROR;
1415 } else
1416 srte_segment_set_local_modification(entry->segment_list, entry,
1417 ted_sid);
1418 return status;
1419 }