1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
8 #include <northbound.h>
11 #include "pceplib/pcep_msg_objects.h"
12 #include "pathd/pathd.h"
13 #include "pathd/path_pcep.h"
14 #include "pathd/path_pcep_config.h"
15 #include "pathd/path_pcep_debug.h"
19 #define MAX_FLOAT_LEN 22
20 #define INETADDR4_MAXLEN 16
21 #define INETADDR6_MAXLEN 40
22 #define INITIATED_CANDIDATE_PREFERENCE 255
23 #define INITIATED_POLICY_COLOR 1
26 static void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
28 static void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
30 static struct path_hop
*
31 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
);
32 static struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
);
33 static char *candidate_name(struct srte_candidate
*candidate
);
34 static enum pcep_lsp_operational_status
35 status_int_to_ext(enum srte_policy_status status
);
36 static enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
);
37 static enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
);
39 void path_pcep_refine_path(struct path
*path
)
41 struct srte_candidate
*candidate
= lookup_candidate(&path
->nbkey
);
44 if (candidate
== NULL
)
49 if (path
->name
== NULL
)
50 path
->name
= candidate_name(candidate
);
51 if (path
->type
== SRTE_CANDIDATE_TYPE_UNDEFINED
)
52 path
->type
= candidate
->type
;
53 if (path
->create_origin
== SRTE_ORIGIN_UNDEFINED
)
54 path
->create_origin
= candidate
->protocol_origin
;
55 if ((path
->update_origin
== SRTE_ORIGIN_UNDEFINED
)
56 && (lsp
->segment_list
!= NULL
))
57 path
->update_origin
= lsp
->segment_list
->protocol_origin
;
60 struct path
*path_pcep_config_get_path(struct lsp_nb_key
*key
)
62 struct srte_candidate
*candidate
= lookup_candidate(key
);
63 if (candidate
== NULL
)
65 return candidate_to_path(candidate
);
68 void path_pcep_config_list_path(path_list_cb_t cb
, void *arg
)
71 struct srte_policy
*policy
;
72 struct srte_candidate
*candidate
;
74 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
75 RB_FOREACH (candidate
, srte_candidate_head
,
76 &policy
->candidate_paths
) {
77 path
= candidate_to_path(candidate
);
84 struct path
*candidate_to_path(struct srte_candidate
*candidate
)
88 struct path_hop
*hop
= NULL
;
89 struct path_metric
*metric
= NULL
;
90 struct srte_policy
*policy
;
92 enum pcep_lsp_operational_status status
;
93 enum srte_protocol_origin update_origin
= 0;
94 char *originator
= NULL
;
96 policy
= candidate
->policy
;
99 if (lsp
->segment_list
!= NULL
) {
100 hop
= path_pcep_config_list_path_hops(lsp
->segment_list
);
101 update_origin
= lsp
->segment_list
->protocol_origin
;
102 originator
= XSTRDUP(MTYPE_PCEP
, lsp
->segment_list
->originator
);
104 path
= pcep_new_path();
105 name
= candidate_name(candidate
);
106 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_BEST
)) {
107 status
= status_int_to_ext(policy
->status
);
109 status
= PCEP_LSP_OPERATIONAL_DOWN
;
111 for (uint32_t i
= 0; i
< MAX_METRIC_TYPE
; i
++) {
112 struct path_metric
*path_metric
;
113 struct srte_metric
*srte_metric
= &lsp
->metrics
[i
];
114 if (CHECK_FLAG(srte_metric
->flags
, F_METRIC_IS_DEFINED
)) {
115 path_metric
= pcep_new_metric();
116 path_metric
->next
= metric
;
117 metric
= path_metric
;
118 metric
->type
= i
+ 1;
119 metric
->value
= srte_metric
->value
;
120 metric
->enforce
= CHECK_FLAG(srte_metric
->flags
,
121 F_METRIC_IS_REQUIRED
);
122 metric
->is_bound
= CHECK_FLAG(srte_metric
->flags
,
124 metric
->is_computed
= CHECK_FLAG(srte_metric
->flags
,
125 F_METRIC_IS_COMPUTED
);
128 *path
= (struct path
){
129 .nbkey
= (struct lsp_nb_key
){.color
= policy
->color
,
130 .endpoint
= policy
->endpoint
,
132 candidate
->preference
},
133 .create_origin
= lsp
->protocol_origin
,
134 .update_origin
= update_origin
,
135 .originator
= originator
,
138 .type
= candidate
->type
,
139 .srp_id
= policy
->srp_id
,
141 .binding_sid
= policy
->binding_sid
,
145 .was_created
= false,
146 .was_removed
= false,
147 .is_synching
= false,
148 .is_delegated
= false,
150 .first_metric
= metric
};
152 path
->has_bandwidth
= CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_BANDWIDTH
);
153 if (path
->has_bandwidth
) {
154 path
->enforce_bandwidth
=
155 CHECK_FLAG(lsp
->flags
, F_CANDIDATE_REQUIRED_BANDWIDTH
);
156 path
->bandwidth
= lsp
->bandwidth
;
158 path
->enforce_bandwidth
= true;
162 copy_candidate_objfun_info(candidate
, path
);
163 copy_candidate_affinity_filters(candidate
, path
);
168 void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
171 struct srte_lsp
*lsp
= candidate
->lsp
;
174 if (CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
175 path
->has_pce_objfun
= true;
176 path
->pce_objfun
= lsp
->objfun
;
178 path
->has_pce_objfun
= false;
179 path
->pce_objfun
= OBJFUN_UNDEFINED
;
182 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
183 path
->has_pcc_objfun
= true;
184 path
->pcc_objfun
= candidate
->objfun
;
185 path
->enforce_pcc_objfun
= CHECK_FLAG(
186 candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
189 path
->has_pcc_objfun
= false;
190 path
->pcc_objfun
= OBJFUN_UNDEFINED
;
191 UNSET_FLAG(candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
195 void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
198 bool eany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_EXCLUDE_ANY
);
199 bool iany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ANY
);
200 bool iall
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ALL
);
201 path
->has_affinity_filters
= eany
|| iany
|| iall
;
202 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
203 eany
? candidate
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
206 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
207 iany
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
210 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
211 iall
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
217 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
)
219 struct srte_segment_entry
*segment
;
220 struct path_hop
*hop
= NULL
, *last_hop
= NULL
;
222 RB_FOREACH_REVERSE (segment
, srte_segment_entry_head
,
223 &segment_list
->segments
) {
224 hop
= pcep_new_hop();
225 *hop
= (struct path_hop
){
230 .has_attribs
= false,
231 .sid
= {.mpls
= {.label
= segment
->sid_value
}},
233 segment
->nai_type
!= SRTE_SEGMENT_NAI_TYPE_NONE
,
234 .nai
= {.type
= pcep_nai_type(segment
->nai_type
)}};
235 switch (segment
->nai_type
) {
236 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
237 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
238 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE
:
239 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE
:
240 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM
:
241 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM
:
242 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
243 sizeof(struct ipaddr
));
245 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
246 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
247 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
248 sizeof(struct ipaddr
));
249 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
250 sizeof(struct ipaddr
));
252 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
253 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
254 sizeof(struct ipaddr
));
255 hop
->nai
.local_iface
= segment
->nai_local_iface
;
256 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
257 sizeof(struct ipaddr
));
258 hop
->nai
.remote_iface
= segment
->nai_remote_iface
;
260 case SRTE_SEGMENT_NAI_TYPE_NONE
:
261 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES
:
269 int path_pcep_config_initiate_path(struct path
*path
)
271 struct srte_policy
*policy
;
272 struct srte_candidate
*candidate
;
274 if (path
->do_remove
) {
275 zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
277 candidate
= lookup_candidate(&path
->nbkey
);
279 if (!path
->is_delegated
) {
281 "(%s)PCE tried to REMOVE but it's not Delegated!",
285 if (candidate
->type
!= SRTE_CANDIDATE_TYPE_DYNAMIC
) {
287 "(%s)PCE tried to REMOVE but it's not PCE origin!",
292 "(%s)PCE tried to REMOVE found candidate!, let's remove",
294 candidate
->policy
->srp_id
= path
->srp_id
;
295 SET_FLAG(candidate
->policy
->flags
, F_POLICY_DELETED
);
296 SET_FLAG(candidate
->flags
, F_CANDIDATE_DELETED
);
298 zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
302 srte_apply_changes();
304 assert(!IS_IPADDR_NONE(&path
->nbkey
.endpoint
));
306 if (path
->nbkey
.preference
== 0)
307 path
->nbkey
.preference
= INITIATED_CANDIDATE_PREFERENCE
;
309 if (path
->nbkey
.color
== 0)
310 path
->nbkey
.color
= INITIATED_POLICY_COLOR
;
312 candidate
= lookup_candidate(&path
->nbkey
);
314 policy
= srte_policy_add(
315 path
->nbkey
.color
, &path
->nbkey
.endpoint
,
316 SRTE_ORIGIN_PCEP
, path
->originator
);
317 strlcpy(policy
->name
, path
->name
, sizeof(policy
->name
));
318 policy
->binding_sid
= path
->binding_sid
;
319 SET_FLAG(policy
->flags
, F_POLICY_NEW
);
320 candidate
= srte_candidate_add(
321 policy
, path
->nbkey
.preference
,
322 SRTE_ORIGIN_PCEP
, path
->originator
);
323 candidate
->policy
->srp_id
= path
->srp_id
;
324 strlcpy(candidate
->name
, path
->name
,
325 sizeof(candidate
->name
));
326 SET_FLAG(candidate
->flags
, F_CANDIDATE_NEW
);
328 policy
= candidate
->policy
;
329 if ((path
->originator
!= candidate
->originator
)
330 || (path
->originator
!= policy
->originator
)) {
331 /* There is already an initiated path from
332 * another PCE, show a warning and regect the
335 "PCE %s tried to initiate a path already initiated by PCE %s",
337 candidate
->originator
);
340 if ((policy
->protocol_origin
!= SRTE_ORIGIN_PCEP
)
341 || (candidate
->protocol_origin
342 != SRTE_ORIGIN_PCEP
)) {
343 /* There is already an initiated path from
344 * another PCE, show a warning and regect the
347 "PCE %s tried to initiate a path created localy",
352 return path_pcep_config_update_path(path
);
357 int path_pcep_config_update_path(struct path
*path
)
359 assert(path
!= NULL
);
360 assert(path
->nbkey
.preference
!= 0);
361 assert(path
->nbkey
.endpoint
.ipa_type
== IPADDR_V4
);
363 int number_of_sid_clashed
= 0;
364 struct path_hop
*hop
;
365 struct path_metric
*metric
;
367 char segment_list_name_buff
[64 + 1 + 64 + 1 + 11 + 1];
368 char *segment_list_name
= NULL
;
369 struct srte_candidate
*candidate
;
370 struct srte_segment_list
*segment_list
= NULL
;
371 struct srte_segment_entry
*segment
;
373 candidate
= lookup_candidate(&path
->nbkey
);
375 // if there is no candidate to update we are done
379 candidate
->policy
->srp_id
= path
->srp_id
;
380 // first clean up old segment list if present
381 if (candidate
->lsp
->segment_list
) {
382 SET_FLAG(candidate
->lsp
->segment_list
->flags
,
383 F_SEGMENT_LIST_DELETED
);
384 srte_segment_list_del(candidate
->lsp
->segment_list
);
385 candidate
->lsp
->segment_list
= NULL
;
388 if (path
->first_hop
== NULL
)
391 snprintf(segment_list_name_buff
, sizeof(segment_list_name_buff
),
392 "%s-%u", path
->name
, path
->plsp_id
);
393 segment_list_name
= segment_list_name_buff
;
395 segment_list
= srte_segment_list_add(segment_list_name
);
396 segment_list
->protocol_origin
= path
->update_origin
;
397 strlcpy(segment_list
->originator
, path
->originator
,
398 sizeof(segment_list
->originator
));
399 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_NEW
);
400 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
402 for (hop
= path
->first_hop
, index
= 10; hop
!= NULL
;
403 hop
= hop
->next
, index
+= 10) {
404 assert(hop
->has_sid
);
405 assert(hop
->is_mpls
);
407 segment
= srte_segment_entry_add(segment_list
, index
);
409 segment
->sid_value
= (mpls_label_t
)hop
->sid
.mpls
.label
;
410 SET_FLAG(segment
->segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
414 if (srte_segment_entry_set_nai(
415 segment
, srte_nai_type(hop
->nai
.type
),
416 &hop
->nai
.local_addr
, hop
->nai
.local_iface
,
417 &hop
->nai
.remote_addr
, hop
->nai
.remote_iface
, 0, 0)
419 /* TED queries don't match PCE */
420 /* Don't apply srte,zebra changes */
421 number_of_sid_clashed
++;
424 candidate
->lsp
->segment_list
= segment_list
;
425 SET_FLAG(candidate
->flags
, F_CANDIDATE_MODIFIED
);
427 for (metric
= path
->first_metric
; metric
!= NULL
; metric
= metric
->next
)
430 (enum srte_candidate_metric_type
)metric
->type
,
431 metric
->value
, metric
->enforce
, metric
->is_bound
,
432 metric
->is_computed
);
434 if (path
->has_bandwidth
)
435 srte_lsp_set_bandwidth(candidate
->lsp
, path
->bandwidth
,
436 path
->enforce_bandwidth
);
438 if (path
->has_pce_objfun
) {
439 SET_FLAG(candidate
->lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
);
440 candidate
->lsp
->objfun
= path
->pce_objfun
;
443 if (number_of_sid_clashed
)
444 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_SID_CONFLICT
);
446 srte_apply_changes();
451 struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
)
453 struct srte_policy
*policy
= NULL
;
454 policy
= srte_policy_find(key
->color
, &key
->endpoint
);
457 return srte_candidate_find(policy
, key
->preference
);
460 char *candidate_name(struct srte_candidate
*candidate
)
462 if (candidate
->protocol_origin
== SRTE_ORIGIN_PCEP
463 || candidate
->protocol_origin
== SRTE_ORIGIN_BGP
)
464 return asprintfrr(MTYPE_PCEP
, "%s", candidate
->policy
->name
);
466 return asprintfrr(MTYPE_PCEP
, "%s-%s", candidate
->policy
->name
,
470 enum pcep_lsp_operational_status
471 status_int_to_ext(enum srte_policy_status status
)
474 case SRTE_POLICY_STATUS_UP
:
475 return PCEP_LSP_OPERATIONAL_ACTIVE
;
476 case SRTE_POLICY_STATUS_GOING_UP
:
477 return PCEP_LSP_OPERATIONAL_GOING_UP
;
478 case SRTE_POLICY_STATUS_GOING_DOWN
:
479 return PCEP_LSP_OPERATIONAL_GOING_DOWN
;
480 case SRTE_POLICY_STATUS_DOWN
:
481 case SRTE_POLICY_STATUS_UNKNOWN
:
482 return PCEP_LSP_OPERATIONAL_DOWN
;
485 assert(!"Reached end of function where we are not expecting to");
488 enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
)
491 case SRTE_SEGMENT_NAI_TYPE_NONE
:
492 return PCEP_SR_SUBOBJ_NAI_ABSENT
;
493 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
494 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
495 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
496 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
497 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
498 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
;
499 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
500 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
;
501 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
502 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
;
503 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES
:
504 return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
;
505 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE
:
506 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
507 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE
:
508 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
509 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM
:
510 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
511 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM
:
512 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
514 return PCEP_SR_SUBOBJ_NAI_UNKNOWN
;
518 enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
)
521 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
522 return SRTE_SEGMENT_NAI_TYPE_NONE
;
523 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
524 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
;
525 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
526 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
;
527 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
528 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
;
529 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
530 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
;
531 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
532 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
;
533 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
:
534 case PCEP_SR_SUBOBJ_NAI_UNKNOWN
:
535 return SRTE_SEGMENT_NAI_TYPE_NONE
;
538 assert(!"Reached end of function where we were not expecting to");