]> git.proxmox.com Git - mirror_frr.git/blame - pathd/pathd.c
pathd: New SR-TE policy management daemon
[mirror_frr.git] / pathd / pathd.c
CommitLineData
4d7b695d
SM
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
25#include "pathd/pathd.h"
26#include "pathd/path_memory.h"
27#include "pathd/path_zebra.h"
28#include "pathd/path_debug.h"
29
30#define HOOK_DELAY 3
31
32DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List")
33DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy")
34DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path")
35
36DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
37 (candidate))
38DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
39 (candidate))
40DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
41 (candidate))
42
43static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
44static int trigger_pathd_candidate_created_timer(struct thread *thread);
45static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
46static int trigger_pathd_candidate_updated_timer(struct thread *thread);
47static void trigger_pathd_candidate_removed(struct srte_candidate *candidate);
48static const char *
49srte_candidate_metric_name(enum srte_candidate_metric_type type);
50
51static void srte_set_metric(struct srte_metric *metric, float value,
52 bool required, bool is_bound, bool is_computed);
53static void srte_unset_metric(struct srte_metric *metric);
54
55
56/* Generate rb-tree of Segment List Segment instances. */
57static inline int srte_segment_entry_compare(const struct srte_segment_entry *a,
58 const struct srte_segment_entry *b)
59{
60 return a->index - b->index;
61}
62RB_GENERATE(srte_segment_entry_head, srte_segment_entry, entry,
63 srte_segment_entry_compare)
64
65/* Generate rb-tree of Segment List instances. */
66static inline int srte_segment_list_compare(const struct srte_segment_list *a,
67 const struct srte_segment_list *b)
68{
69 return strcmp(a->name, b->name);
70}
71RB_GENERATE(srte_segment_list_head, srte_segment_list, entry,
72 srte_segment_list_compare)
73
74struct srte_segment_list_head srte_segment_lists =
75 RB_INITIALIZER(&srte_segment_lists);
76
77/* Generate rb-tree of Candidate Path instances. */
78static inline int srte_candidate_compare(const struct srte_candidate *a,
79 const struct srte_candidate *b)
80{
81 return a->preference - b->preference;
82}
83RB_GENERATE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
84
85/* Generate rb-tree of SR Policy instances. */
86static inline int srte_policy_compare(const struct srte_policy *a,
87 const struct srte_policy *b)
88{
89 return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
90 b->color);
91}
92RB_GENERATE(srte_policy_head, srte_policy, entry, srte_policy_compare)
93
94struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
95
96/**
97 * Adds a segment list to pathd.
98 *
99 * @param name The name of the segment list to add
100 * @return The added segment list
101 */
102struct srte_segment_list *srte_segment_list_add(const char *name)
103{
104 struct srte_segment_list *segment_list;
105
106 segment_list = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment_list));
107 strlcpy(segment_list->name, name, sizeof(segment_list->name));
108 RB_INIT(srte_segment_entry_head, &segment_list->segments);
109 RB_INSERT(srte_segment_list_head, &srte_segment_lists, segment_list);
110
111 return segment_list;
112}
113
114/**
115 * Deletes a segment list from pathd.
116 *
117 * The given segment list structure will be freed and should not be used anymore
118 * after calling this function.
119 *
120 * @param segment_list the segment list to remove from pathd.
121 */
122void srte_segment_list_del(struct srte_segment_list *segment_list)
123{
124 struct srte_segment_entry *segment, *safe_seg;
125 RB_FOREACH_SAFE (segment, srte_segment_entry_head,
126 &segment_list->segments, safe_seg) {
127 srte_segment_entry_del(segment);
128 }
129 RB_REMOVE(srte_segment_list_head, &srte_segment_lists, segment_list);
130 XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list);
131}
132
133/**
134 * Search for a segment list by name.
135 *
136 * @param name The name of the segment list to look for
137 * @return The segment list if found, NULL otherwise
138 */
139struct srte_segment_list *srte_segment_list_find(const char *name)
140{
141 struct srte_segment_list search;
142
143 strlcpy(search.name, name, sizeof(search.name));
144 return RB_FIND(srte_segment_list_head, &srte_segment_lists, &search);
145}
146
147/**
148 * Adds a segment to a segment list.
149 *
150 * @param segment_list The segment list the segment should be added to
151 * @param index The index of the added segment in the segment list
152 * @return The added segment
153 */
154struct srte_segment_entry *
155srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index)
156{
157 struct srte_segment_entry *segment;
158
159 segment = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment));
160 segment->segment_list = segment_list;
161 segment->index = index;
162 RB_INSERT(srte_segment_entry_head, &segment_list->segments, segment);
163
164 return segment;
165}
166
167/**
168 * Deletes a segment from a segment list.
169 *
170 * @param segment The segment to be removed
171 */
172void srte_segment_entry_del(struct srte_segment_entry *segment)
173{
174 RB_REMOVE(srte_segment_entry_head, &segment->segment_list->segments,
175 segment);
176 XFREE(MTYPE_PATH_SEGMENT_LIST, segment);
177}
178
179/**
180 * Set the node or adjacency identifier of a segment.
181 *
182 * @param segment The segment for which the NAI should be set
183 * @param type The type of the NAI
184 * @param type The address of the node or the local address of the adjacency
185 * @param type The local interface index of the unumbered adjacency
186 * @param type The remote address of the adjacency
187 * @param type The remote interface index of the unumbered adjacency
188 */
189void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
190 enum srte_segment_nai_type type,
191 struct ipaddr *local_ip, uint32_t local_iface,
192 struct ipaddr *remote_ip, uint32_t remote_iface)
193{
194 segment->nai_type = type;
195 memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr));
196
197 switch (type) {
198 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
199 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
200 break;
201 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
202 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
203 memcpy(&segment->nai_remote_addr, remote_ip,
204 sizeof(struct ipaddr));
205 break;
206 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
207 memcpy(&segment->nai_remote_addr, remote_ip,
208 sizeof(struct ipaddr));
209 segment->nai_local_iface = local_iface;
210 segment->nai_remote_iface = remote_iface;
211 break;
212 default:
213 segment->nai_local_addr.ipa_type = IPADDR_NONE;
214 segment->nai_local_iface = 0;
215 segment->nai_remote_addr.ipa_type = IPADDR_NONE;
216 segment->nai_remote_iface = 0;
217 }
218}
219
220/**
221 * Add a policy to pathd.
222 *
223 * WARNING: The color 0 is a special case as it is the no-color.
224 *
225 * @param color The color of the policy.
226 * @param endpoint The IP address of the policy endpoint
227 * @return The created policy
228 */
229struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint)
230{
231 struct srte_policy *policy;
232
233 policy = XCALLOC(MTYPE_PATH_SR_POLICY, sizeof(*policy));
234 policy->color = color;
235 policy->endpoint = *endpoint;
236 policy->binding_sid = MPLS_LABEL_NONE;
237 RB_INIT(srte_candidate_head, &policy->candidate_paths);
238 RB_INSERT(srte_policy_head, &srte_policies, policy);
239
240 return policy;
241}
242
243/**
244 * Delete a policy from pathd.
245 *
246 * The given policy structure will be freed and should never be used again
247 * after calling this function.
248 *
249 * @param policy The policy to be removed
250 */
251void srte_policy_del(struct srte_policy *policy)
252{
253 struct srte_candidate *candidate;
254
255 path_zebra_delete_sr_policy(policy);
256
257 path_zebra_release_label(policy->binding_sid);
258
259 while (!RB_EMPTY(srte_candidate_head, &policy->candidate_paths)) {
260 candidate =
261 RB_ROOT(srte_candidate_head, &policy->candidate_paths);
262 trigger_pathd_candidate_removed(candidate);
263 srte_candidate_del(candidate);
264 }
265
266 RB_REMOVE(srte_policy_head, &srte_policies, policy);
267 XFREE(MTYPE_PATH_SR_POLICY, policy);
268}
269
270/**
271 * Search for a policy by color and endpoint.
272 *
273 * WARNING: The color 0 is a special case as it is the no-color.
274 *
275 * @param color The color of the policy to look for
276 * @param endpoint The endpoint of the policy to look for
277 * @return The policy if found, NULL otherwise
278 */
279struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint)
280{
281 struct srte_policy search;
282
283 search.color = color;
284 search.endpoint = *endpoint;
285 return RB_FIND(srte_policy_head, &srte_policies, &search);
286}
287
288/**
289 * Update a policy binding SID.
290 *
291 * @param policy The policy for which the SID should be updated
292 * @param binding_sid The new binding SID for the given policy
293 */
294void srte_policy_update_binding_sid(struct srte_policy *policy,
295 uint32_t binding_sid)
296{
297 if (policy->binding_sid != MPLS_LABEL_NONE)
298 path_zebra_release_label(policy->binding_sid);
299
300 policy->binding_sid = binding_sid;
301
302 /* Reinstall the Binding-SID if necessary. */
303 if (policy->best_candidate)
304 path_zebra_add_sr_policy(
305 policy, policy->best_candidate->lsp->segment_list);
306}
307
308/**
309 * Gives the policy best candidate path.
310 *
311 * @param policy The policy we want the best candidate path from
312 * @return The best candidate path
313 */
314static struct srte_candidate *
315srte_policy_best_candidate(const struct srte_policy *policy)
316{
317 struct srte_candidate *candidate;
318
319 RB_FOREACH_REVERSE (candidate, srte_candidate_head,
320 &policy->candidate_paths) {
321 /* search for highest preference with existing segment list */
322 if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)
323 && candidate->lsp->segment_list)
324 return candidate;
325 }
326
327 return NULL;
328}
329
330/**
331 * Apply changes defined by setting the policies, candidate paths
332 * and segment lists modification flags NEW, MODIFIED and DELETED.
333 *
334 * This allows the northbound code to delay all the side effects of adding
335 * modifying and deleting them to the end.
336 *
337 * Example of marking an object as modified:
338 * `SET_FLAG(obj->flags, F_XXX_MODIFIED)`
339 */
340void srte_apply_changes(void)
341{
342 struct srte_policy *policy, *safe_pol;
343 struct srte_segment_list *segment_list, *safe_sl;
344
345 RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
346 if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
347 srte_policy_del(policy);
348 continue;
349 }
350 srte_policy_apply_changes(policy);
351 UNSET_FLAG(policy->flags, F_POLICY_NEW);
352 UNSET_FLAG(policy->flags, F_POLICY_MODIFIED);
353 }
354
355 RB_FOREACH_SAFE (segment_list, srte_segment_list_head,
356 &srte_segment_lists, safe_sl) {
357 if (CHECK_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED)) {
358 srte_segment_list_del(segment_list);
359 continue;
360 }
361 UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
362 UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
363 }
364}
365
366/**
367 * Apply changes defined by setting the given policy and its candidate paths
368 * modification flags NEW, MODIFIED and DELETED.
369 *
370 * In moste cases `void srte_apply_changes(void)` should be used instead,
371 * this function will not handle the changes of segment lists used by the
372 * policy.
373 *
374 * @param policy The policy changes has to be applied to.
375 */
376void srte_policy_apply_changes(struct srte_policy *policy)
377{
378 struct srte_candidate *candidate, *safe;
379 struct srte_candidate *old_best_candidate;
380 struct srte_candidate *new_best_candidate;
381 char endpoint[46];
382
383 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
384
385 /* Get old and new best candidate path. */
386 old_best_candidate = policy->best_candidate;
387 new_best_candidate = srte_policy_best_candidate(policy);
388
389 if (new_best_candidate != old_best_candidate) {
390 /* TODO: add debug guard. */
391 zlog_debug(
392 "SR-TE(%s, %u): best candidate changed from %s to %s",
393 endpoint, policy->color,
394 old_best_candidate ? old_best_candidate->name : "none",
395 new_best_candidate ? new_best_candidate->name : "none");
396
397 if (old_best_candidate) {
398 policy->best_candidate = NULL;
399 UNSET_FLAG(old_best_candidate->flags, F_CANDIDATE_BEST);
400 SET_FLAG(old_best_candidate->flags,
401 F_CANDIDATE_MODIFIED);
402
403 /*
404 * Rely on replace semantics if there's a new best
405 * candidate.
406 */
407 if (!new_best_candidate)
408 path_zebra_delete_sr_policy(policy);
409 }
410 if (new_best_candidate) {
411 policy->best_candidate = new_best_candidate;
412 SET_FLAG(new_best_candidate->flags, F_CANDIDATE_BEST);
413 SET_FLAG(new_best_candidate->flags,
414 F_CANDIDATE_MODIFIED);
415
416 path_zebra_add_sr_policy(
417 policy, new_best_candidate->lsp->segment_list);
418 }
419 } else if (new_best_candidate) {
420 /* The best candidate path did not change, but some of its
421 * attributes or its segment list may have changed.
422 */
423
424 bool candidate_changed = CHECK_FLAG(new_best_candidate->flags,
425 F_CANDIDATE_MODIFIED);
426 bool segment_list_changed =
427 new_best_candidate->lsp->segment_list
428 && CHECK_FLAG(
429 new_best_candidate->lsp->segment_list->flags,
430 F_SEGMENT_LIST_MODIFIED);
431
432 if (candidate_changed || segment_list_changed) {
433 /* TODO: add debug guard. */
434 zlog_debug("SR-TE(%s, %u): best candidate %s changed",
435 endpoint, policy->color,
436 new_best_candidate->name);
437
438 path_zebra_add_sr_policy(
439 policy, new_best_candidate->lsp->segment_list);
440 }
441 }
442
443 RB_FOREACH_SAFE (candidate, srte_candidate_head,
444 &policy->candidate_paths, safe) {
445 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)) {
446 trigger_pathd_candidate_removed(candidate);
447 srte_candidate_del(candidate);
448 continue;
449 } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_NEW)) {
450 trigger_pathd_candidate_created(candidate);
451 } else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_MODIFIED)) {
452 trigger_pathd_candidate_updated(candidate);
453 } else if (candidate->lsp->segment_list
454 && CHECK_FLAG(candidate->lsp->segment_list->flags,
455 F_SEGMENT_LIST_MODIFIED)) {
456 trigger_pathd_candidate_updated(candidate);
457 }
458
459 UNSET_FLAG(candidate->flags, F_CANDIDATE_NEW);
460 UNSET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
461 }
462}
463
464/**
465 * Adds a candidate path to a policy.
466 *
467 * @param policy The policy the candidate path should be added to
468 * @param preference The preference of the candidate path to be added
469 * @return The added candidate path
470 */
471struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
472 uint32_t preference)
473{
474 struct srte_candidate *candidate;
475 struct srte_lsp *lsp;
476
477 candidate = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*candidate));
478 lsp = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*lsp));
479
480 candidate->preference = preference;
481 candidate->policy = policy;
482 candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
483 candidate->discriminator = rand();
484
485 lsp->candidate = candidate;
486 candidate->lsp = lsp;
487
488 RB_INSERT(srte_candidate_head, &policy->candidate_paths, candidate);
489
490 return candidate;
491}
492
493/**
494 * Deletes a candidate.
495 *
496 * The corresponding LSP will be removed alongside the candidate path.
497 * The given candidate will be freed and shouldn't be used anymore after the
498 * calling this function.
499 *
500 * @param candidate The candidate path to delete
501 */
502void srte_candidate_del(struct srte_candidate *candidate)
503{
504 struct srte_policy *srte_policy = candidate->policy;
505
506 RB_REMOVE(srte_candidate_head, &srte_policy->candidate_paths,
507 candidate);
508
509 XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp);
510 XFREE(MTYPE_PATH_SR_CANDIDATE, candidate);
511}
512
513/**
514 * Sets the bandwidth constraint of given candidate path.
515 *
516 * The corresponding LSP will be changed too.
517 *
518 * @param candidate The candidate path of which the bandwidth should be changed
519 * @param bandwidth The Bandwidth constraint to set to the candidate path
520 * @param required If the constraint is required (true) or only desired (false)
521 */
522void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
523 float bandwidth, bool required)
524{
525 struct srte_policy *policy = candidate->policy;
526 char endpoint[46];
527 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
528 zlog_debug(
529 "SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
530 endpoint, policy->color, candidate->name,
531 required ? "required " : "", bandwidth);
532 SET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
533 COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
534 candidate->bandwidth = bandwidth;
535
536 srte_lsp_set_bandwidth(candidate->lsp, bandwidth, required);
537}
538
539/**
540 * Sets the bandwidth constraint of the given LSP.
541 *
542 * The changes will not be shown as part of the running configuration.
543 *
544 * @param lsp The lsp of which the bandwidth should be changed
545 * @param bandwidth The Bandwidth constraint to set to the candidate path
546 * @param required If the constraint is required (true) or only desired (false)
547 */
548void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
549 bool required)
550{
551 struct srte_candidate *candidate = lsp->candidate;
552 struct srte_policy *policy = candidate->policy;
553 char endpoint[46];
554 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
555 zlog_debug("SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
556 endpoint, policy->color, candidate->name,
557 required ? "required" : "", bandwidth);
558 SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
559 COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
560 lsp->bandwidth = bandwidth;
561}
562
563/**
564 * Remove a candidate path bandwidth constraint.
565 *
566 * The corresponding LSP will be changed too.
567 *
568 * @param candidate The candidate path of which the bandwidth should be removed
569 */
570void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
571{
572 struct srte_policy *policy = candidate->policy;
573 char endpoint[46];
574 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
575 zlog_debug("SR-TE(%s, %u): candidate %s config bandwidth unset",
576 endpoint, policy->color, candidate->name);
577 UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
578 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
579 candidate->bandwidth = 0;
580 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
581 srte_lsp_unset_bandwidth(candidate->lsp);
582}
583
584/**
585 * Remove an LSP bandwidth constraint.
586 *
587 * The changes will not be shown as part of the running configuration.
588 *
589 * @param lsp The lsp of which the bandwidth should be changed
590 */
591void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
592{
593 struct srte_candidate *candidate = lsp->candidate;
594 struct srte_policy *policy = candidate->policy;
595 char endpoint[46];
596 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
597 zlog_debug("SR-TE(%s, %u): candidate %s lsp bandwidth unset", endpoint,
598 policy->color, candidate->name);
599 UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
600 UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
601 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
602 lsp->bandwidth = 0;
603}
604
605/**
606 * Sets a candidate path metric constraint.
607 *
608 * The corresponding LSP will be changed too.
609 *
610 * @param candidate The candidate path of which the metric should be changed
611 * @param type The metric type
612 * @param value The metric value
613 * @param required If the constraint is required (true) or only desired (false)
614 * @param is_bound If the metric is an indicative value or a strict upper bound
615 * @param is_computed If the metric was computed or configured
616 */
617void srte_candidate_set_metric(struct srte_candidate *candidate,
618 enum srte_candidate_metric_type type,
619 float value, bool required, bool is_bound,
620 bool is_computed)
621{
622 struct srte_policy *policy = candidate->policy;
623 char endpoint[46];
624 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
625 zlog_debug(
626 "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f "
627 "(is-bound: %s; is_computed: %s)",
628 endpoint, policy->color, candidate->name,
629 required ? "required " : "", srte_candidate_metric_name(type),
630 type, value, is_bound ? "true" : "false",
631 is_computed ? "true" : "false");
632 assert((type > 0) && (type <= MAX_METRIC_TYPE));
633 srte_set_metric(&candidate->metrics[type - 1], value, required,
634 is_bound, is_computed);
635 srte_lsp_set_metric(candidate->lsp, type, value, required, is_bound,
636 is_computed);
637 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
638}
639
640/**
641 * Sets an LSP metric constraint.
642 *
643 * The changes will not be shown as part of the running configuration.
644 *
645 * @param lsp The LSP of which the metric should be changed
646 * @param type The metric type
647 * @param value The metric value
648 * @param required If the constraint is required (true) or only desired (false)
649 * @param is_bound If the metric is an indicative value or a strict upper bound
650 * @param is_computed If the metric was computed or configured
651 */
652void srte_lsp_set_metric(struct srte_lsp *lsp,
653 enum srte_candidate_metric_type type, float value,
654 bool required, bool is_bound, bool is_computed)
655{
656 struct srte_candidate *candidate = lsp->candidate;
657 struct srte_policy *policy = candidate->policy;
658 char endpoint[46];
659 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
660 zlog_debug(
661 "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f "
662 "(is-bound: %s; is_computed: %s)",
663 endpoint, policy->color, candidate->name,
664 required ? "required " : "", srte_candidate_metric_name(type),
665 type, value, is_bound ? "true" : "false",
666 is_computed ? "true" : "false");
667 assert((type > 0) && (type <= MAX_METRIC_TYPE));
668 srte_set_metric(&lsp->metrics[type - 1], value, required, is_bound,
669 is_computed);
670}
671
672void srte_set_metric(struct srte_metric *metric, float value, bool required,
673 bool is_bound, bool is_computed)
674{
675 SET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
676 COND_FLAG(metric->flags, F_METRIC_IS_REQUIRED, required);
677 COND_FLAG(metric->flags, F_METRIC_IS_BOUND, is_bound);
678 COND_FLAG(metric->flags, F_METRIC_IS_COMPUTED, is_computed);
679 metric->value = value;
680}
681
682/**
683 * Removes a candidate path metric constraint.
684 *
685 * The corresponding LSP will be changed too.
686 *
687 * @param candidate The candidate path from which the metric should be removed
688 * @param type The metric type
689 */
690void srte_candidate_unset_metric(struct srte_candidate *candidate,
691 enum srte_candidate_metric_type type)
692{
693 struct srte_policy *policy = candidate->policy;
694 char endpoint[46];
695 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
696 zlog_debug("SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
697 endpoint, policy->color, candidate->name,
698 srte_candidate_metric_name(type), type);
699 assert((type > 0) && (type <= MAX_METRIC_TYPE));
700 srte_unset_metric(&candidate->metrics[type - 1]);
701 srte_lsp_unset_metric(candidate->lsp, type);
702 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
703}
704
705/**
706 * Removes a candidate path metric constraint.
707 *
708 * The changes will not be shown as part of the running configuration.
709 *
710 * @param lsp The LSP from which the metric should be removed
711 * @param type The metric type
712 */
713void srte_lsp_unset_metric(struct srte_lsp *lsp,
714 enum srte_candidate_metric_type type)
715{
716 struct srte_candidate *candidate = lsp->candidate;
717 struct srte_policy *policy = candidate->policy;
718 char endpoint[46];
719 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
720 zlog_debug("SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
721 endpoint, policy->color, candidate->name,
722 srte_candidate_metric_name(type), type);
723 assert((type > 0) && (type <= MAX_METRIC_TYPE));
724 srte_unset_metric(&lsp->metrics[type - 1]);
725}
726
727void srte_unset_metric(struct srte_metric *metric)
728{
729 UNSET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
730 UNSET_FLAG(metric->flags, F_METRIC_IS_BOUND);
731 UNSET_FLAG(metric->flags, F_METRIC_IS_COMPUTED);
732 metric->value = 0;
733}
734
735/**
736 * Sets a candidate path objective function.
737 *
738 * @param candidate The candidate path of which the OF should be changed
739 * @param required If the constraint is required (true) or only desired (false)
740 * @param type The objective function type
741 */
742void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
743 enum objfun_type type)
744{
745 struct srte_policy *policy = candidate->policy;
746 char endpoint[46];
747 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
748
749 candidate->objfun = type;
750 SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
751 COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
752 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
753 zlog_debug("SR-TE(%s, %u): candidate %s %sobjective function set to %s",
754 endpoint, policy->color, candidate->name,
755 required ? "required " : "", objfun_type_name(type));
756}
757
758/**
759 * Removed the objective function constraint from a candidate path.
760 *
761 * @param candidate The candidate path from which the OF should be removed
762 */
763void srte_candidate_unset_objfun(struct srte_candidate *candidate)
764{
765 struct srte_policy *policy = candidate->policy;
766 char endpoint[46];
767 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
768
769 UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
770 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
771 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
772 candidate->objfun = OBJFUN_UNDEFINED;
773 zlog_debug(
774 "SR-TE(%s, %u): candidate %s objective functions preferences unset",
775 endpoint, policy->color, candidate->name);
776}
777
778static uint32_t filter_type_to_flag(enum affinity_filter_type type)
779{
780 switch (type) {
781 case AFFINITY_FILTER_EXCLUDE_ANY:
782 return F_CANDIDATE_HAS_EXCLUDE_ANY;
783 case AFFINITY_FILTER_INCLUDE_ANY:
784 return F_CANDIDATE_HAS_INCLUDE_ANY;
785 case AFFINITY_FILTER_INCLUDE_ALL:
786 return F_CANDIDATE_HAS_INCLUDE_ALL;
787 default:
788 return 0;
789 }
790}
791
792static const char *filter_type_name(enum affinity_filter_type type)
793{
794 switch (type) {
795 case AFFINITY_FILTER_EXCLUDE_ANY:
796 return "exclude-any";
797 case AFFINITY_FILTER_INCLUDE_ANY:
798 return "include-any";
799 case AFFINITY_FILTER_INCLUDE_ALL:
800 return "include-all";
801 default:
802 return "unknown";
803 }
804}
805
806/**
807 * Sets a candidate path affinity filter constraint.
808 *
809 * @param candidate The candidate path of which the constraint should be changed
810 * @param type The affinity constraint type to set
811 * @param filter The bitmask filter of the constraint
812 */
813void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
814 enum affinity_filter_type type,
815 uint32_t filter)
816{
817 struct srte_policy *policy = candidate->policy;
818 char endpoint[46];
819 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
820
821 assert(type > AFFINITY_FILTER_UNDEFINED);
822 assert(type <= MAX_AFFINITY_FILTER_TYPE);
823 SET_FLAG(candidate->flags, filter_type_to_flag(type));
824 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
825 candidate->affinity_filters[type - 1] = filter;
826 zlog_debug(
827 "SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
828 endpoint, policy->color, candidate->name,
829 filter_type_name(type), filter);
830}
831
832/**
833 * Removes a candidate path affinity filter constraint.
834 *
835 * @param candidate The candidate path from which the constraint should be
836 * removed
837 * @param type The affinity constraint type to remove
838 */
839void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
840 enum affinity_filter_type type)
841{
842 struct srte_policy *policy = candidate->policy;
843 char endpoint[46];
844 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
845
846 assert(type > AFFINITY_FILTER_UNDEFINED);
847 assert(type <= MAX_AFFINITY_FILTER_TYPE);
848 UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
849 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
850 candidate->affinity_filters[type - 1] = 0;
851 zlog_debug("SR-TE(%s, %u): candidate %s affinity filter %s unset",
852 endpoint, policy->color, candidate->name,
853 filter_type_name(type));
854}
855
856/**
857 * Searches for a candidate path of the given policy.
858 *
859 * @param policy The policy to search for candidate path
860 * @param preference The preference of the candidate path you are looking for
861 * @return The candidate path if found, NULL otherwise
862 */
863struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
864 uint32_t preference)
865{
866 struct srte_candidate search;
867
868 search.preference = preference;
869 return RB_FIND(srte_candidate_head, &policy->candidate_paths, &search);
870}
871
872/**
873 * Searches for a an entry of a given segment list.
874 *
875 * @param segment_list The segment list to search for the entry
876 * @param index The index of the entry you are looking for
877 * @return The segment list entry if found, NULL otherwise.
878 */
879struct srte_segment_entry *
880srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
881{
882 struct srte_segment_entry search;
883
884 search.index = index;
885 return RB_FIND(srte_segment_entry_head, &segment_list->segments,
886 &search);
887}
888
889/**
890 * Updates a candidate status.
891 *
892 * @param candidate The candidate of which the status should be updated
893 * @param status The new candidate path status
894 */
895void srte_candidate_status_update(struct srte_candidate *candidate, int status)
896{
897 struct srte_policy *policy = candidate->policy;
898 char endpoint[46];
899 ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
900 zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
901 policy->color, status);
902 switch (status) {
903 case ZEBRA_SR_POLICY_DOWN:
904 switch (policy->status) {
905 /* If the policy is GOING_UP, and zebra faild
906 to install it, we wait for zebra to retry */
907 /* TODO: Add some timeout after which we would
908 get is back to DOWN and remove the
909 policy */
910 case SRTE_POLICY_STATUS_GOING_UP:
911 case SRTE_POLICY_STATUS_DOWN:
912 return;
913 default:
914 zlog_debug("SR-TE(%s, %u): policy is DOWN", endpoint,
915 policy->color);
916 policy->status = SRTE_POLICY_STATUS_DOWN;
917 break;
918 }
919 break;
920 case ZEBRA_SR_POLICY_UP:
921 switch (policy->status) {
922 case SRTE_POLICY_STATUS_UP:
923 return;
924 default:
925 zlog_debug("SR-TE(%s, %u): policy is UP", endpoint,
926 policy->color);
927 policy->status = SRTE_POLICY_STATUS_UP;
928 break;
929 }
930 break;
931 }
932
933 trigger_pathd_candidate_updated(candidate);
934}
935
936/**
937 * Flags the segment lists from give originator for removal.
938 *
939 * The function srte_apply_changes must be called afterward for
940 * the segment list to be removed.
941 *
942 * @param originator The originator tag of the segment list to be marked
943 * @param force If the unset should be forced regardless of the originator
944 */
945void srte_candidate_unset_segment_list(const char *originator, bool force)
946{
947 if (originator == NULL) {
948 zlog_warn(
949 "Cannot unset segment list because originator is NULL");
950 return;
951 }
952
953 zlog_debug("Unset segment lists for originator %s", originator);
954
955 /* Iterate the policies, then iterate each policy's candidate path
956 * to check the candidate path's segment list originator */
957 struct srte_policy *policy;
958 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
959 zlog_debug("Unset segment lists checking policy %s",
960 policy->name);
961 struct srte_candidate *candidate;
962 RB_FOREACH (candidate, srte_candidate_head,
963 &policy->candidate_paths) {
964 zlog_debug("Unset segment lists checking candidate %s",
965 candidate->name);
966 if (candidate->lsp == NULL) {
967 continue;
968 }
969
970 /* The candidate->lsp->segment_list is operational data,
971 * configured by the PCE. We dont want to modify the
972 * candidate->segment_list,
973 * which is configuration data. */
974 struct srte_segment_list *segment_list =
975 candidate->lsp->segment_list;
976 if (segment_list == NULL) {
977 continue;
978 }
979
980 if (segment_list->protocol_origin
981 == SRTE_ORIGIN_LOCAL) {
982 zlog_warn(
983 "Cannot unset segment list %s because it "
984 "was created locally",
985 segment_list->name);
986 continue;
987 }
988
989 /* In the case of last pce,we force the unset
990 * because we don't have pce by prefix (TODO) is all
991 * 'global' */
992 if (strncmp(segment_list->originator, originator,
993 sizeof(segment_list->originator))
994 == 0
995 || force) {
996 zlog_debug("Unset segment list %s",
997 segment_list->name);
998 SET_FLAG(segment_list->flags,
999 F_SEGMENT_LIST_DELETED);
1000 SET_FLAG(candidate->flags,
1001 F_CANDIDATE_MODIFIED);
1002 candidate->lsp->segment_list = NULL;
1003 }
1004 }
1005 }
1006}
1007
1008/**
1009 * Gives a string representation of given protocol origin enum.
1010 *
1011 * @param origin The enum you want a string representation of
1012 * @return The string representation of given enum
1013 */
1014const char *srte_origin2str(enum srte_protocol_origin origin)
1015{
1016 switch (origin) {
1017 case SRTE_ORIGIN_PCEP:
1018 return "PCEP";
1019 case SRTE_ORIGIN_BGP:
1020 return "BGP";
1021 case SRTE_ORIGIN_LOCAL:
1022 return "Local";
1023 default:
1024 return "Unknown";
1025 }
1026}
1027
1028void trigger_pathd_candidate_created(struct srte_candidate *candidate)
1029{
1030 /* The hook is called asynchronously to let the PCEP module
1031 time to send a response to the PCE before receiving any updates from
1032 pathd. In addition, a minimum amount of time need to pass before
1033 the hook is called to prevent the hook to be called multiple times
1034 from changing the candidate by hand with the console */
1035 if (candidate->hook_timer != NULL)
1036 return;
1037 thread_add_timer(master, trigger_pathd_candidate_created_timer,
1038 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
1039}
1040
1041int trigger_pathd_candidate_created_timer(struct thread *thread)
1042{
1043 struct srte_candidate *candidate = THREAD_ARG(thread);
1044 candidate->hook_timer = NULL;
1045 return hook_call(pathd_candidate_created, candidate);
1046}
1047
1048void trigger_pathd_candidate_updated(struct srte_candidate *candidate)
1049{
1050 /* The hook is called asynchronously to let the PCEP module
1051 time to send a response to the PCE before receiving any updates from
1052 pathd. In addition, a minimum amount of time need to pass before
1053 the hook is called to prevent the hook to be called multiple times
1054 from changing the candidate by hand with the console */
1055 if (candidate->hook_timer != NULL)
1056 return;
1057 thread_add_timer(master, trigger_pathd_candidate_updated_timer,
1058 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
1059}
1060
1061int trigger_pathd_candidate_updated_timer(struct thread *thread)
1062{
1063 struct srte_candidate *candidate = THREAD_ARG(thread);
1064 candidate->hook_timer = NULL;
1065 return hook_call(pathd_candidate_updated, candidate);
1066}
1067
1068void trigger_pathd_candidate_removed(struct srte_candidate *candidate)
1069{
1070 /* The hook needs to be call synchronously, otherwise the candidate
1071 path will be already deleted when the handler is called */
1072 if (candidate->hook_timer != NULL) {
1073 thread_cancel(&candidate->hook_timer);
1074 candidate->hook_timer = NULL;
1075 }
1076 hook_call(pathd_candidate_removed, candidate);
1077}
1078
1079const char *srte_candidate_metric_name(enum srte_candidate_metric_type type)
1080{
1081 switch (type) {
1082 case SRTE_CANDIDATE_METRIC_TYPE_IGP:
1083 return "IGP";
1084 case SRTE_CANDIDATE_METRIC_TYPE_TE:
1085 return "TE";
1086 case SRTE_CANDIDATE_METRIC_TYPE_HC:
1087 return "HC";
1088 case SRTE_CANDIDATE_METRIC_TYPE_ABC:
1089 return "ABC";
1090 case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
1091 return "LMLL";
1092 case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
1093 return "CIGP";
1094 case SRTE_CANDIDATE_METRIC_TYPE_CTE:
1095 return "CTE";
1096 case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
1097 return "PIGP";
1098 case SRTE_CANDIDATE_METRIC_TYPE_PTE:
1099 return "PTE";
1100 case SRTE_CANDIDATE_METRIC_TYPE_PHC:
1101 return "PHC";
1102 case SRTE_CANDIDATE_METRIC_TYPE_MSD:
1103 return "MSD";
1104 case SRTE_CANDIDATE_METRIC_TYPE_PD:
1105 return "PD";
1106 case SRTE_CANDIDATE_METRIC_TYPE_PDV:
1107 return "PDV";
1108 case SRTE_CANDIDATE_METRIC_TYPE_PL:
1109 return "PL";
1110 case SRTE_CANDIDATE_METRIC_TYPE_PPD:
1111 return "PPD";
1112 case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
1113 return "PPDV";
1114 case SRTE_CANDIDATE_METRIC_TYPE_PPL:
1115 return "PPL";
1116 case SRTE_CANDIDATE_METRIC_TYPE_NAP:
1117 return "NAP";
1118 case SRTE_CANDIDATE_METRIC_TYPE_NLP:
1119 return "NLP";
1120 case SRTE_CANDIDATE_METRIC_TYPE_DC:
1121 return "DC";
1122 case SRTE_CANDIDATE_METRIC_TYPE_BNC:
1123 return "BNC";
1124 default:
1125 return "UNKNOWN";
1126 }
1127}