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