2 * Copyright (C) 2020 NetDEF, Inc.
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)
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
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
21 #include <northbound.h>
24 #include "pceplib/pcep_msg_objects.h"
25 #include "pathd/pathd.h"
26 #include "pathd/path_pcep.h"
27 #include "pathd/path_pcep_config.h"
28 #include "pathd/path_pcep_debug.h"
32 #define MAX_FLOAT_LEN 22
33 #define INETADDR4_MAXLEN 16
34 #define INETADDR6_MAXLEN 40
35 #define INITIATED_CANDIDATE_PREFERENCE 255
36 #define INITIATED_POLICY_COLOR 1
39 static void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
41 static void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
43 static struct path_hop
*
44 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
);
45 static struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
);
46 static char *candidate_name(struct srte_candidate
*candidate
);
47 static enum pcep_lsp_operational_status
48 status_int_to_ext(enum srte_policy_status status
);
49 static enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
);
50 static enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
);
52 void path_pcep_refine_path(struct path
*path
)
54 struct srte_candidate
*candidate
= lookup_candidate(&path
->nbkey
);
57 if (candidate
== NULL
)
62 if (path
->name
== NULL
)
63 path
->name
= candidate_name(candidate
);
64 if (path
->type
== SRTE_CANDIDATE_TYPE_UNDEFINED
)
65 path
->type
= candidate
->type
;
66 if (path
->create_origin
== SRTE_ORIGIN_UNDEFINED
)
67 path
->create_origin
= candidate
->protocol_origin
;
68 if ((path
->update_origin
== SRTE_ORIGIN_UNDEFINED
)
69 && (lsp
->segment_list
!= NULL
))
70 path
->update_origin
= lsp
->segment_list
->protocol_origin
;
73 struct path
*path_pcep_config_get_path(struct lsp_nb_key
*key
)
75 struct srte_candidate
*candidate
= lookup_candidate(key
);
76 if (candidate
== NULL
)
78 return candidate_to_path(candidate
);
81 void path_pcep_config_list_path(path_list_cb_t cb
, void *arg
)
84 struct srte_policy
*policy
;
85 struct srte_candidate
*candidate
;
87 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
88 RB_FOREACH (candidate
, srte_candidate_head
,
89 &policy
->candidate_paths
) {
90 path
= candidate_to_path(candidate
);
97 struct path
*candidate_to_path(struct srte_candidate
*candidate
)
101 struct path_hop
*hop
= NULL
;
102 struct path_metric
*metric
= NULL
;
103 struct srte_policy
*policy
;
104 struct srte_lsp
*lsp
;
105 enum pcep_lsp_operational_status status
;
106 enum srte_protocol_origin update_origin
= 0;
107 char *originator
= NULL
;
109 policy
= candidate
->policy
;
110 lsp
= candidate
->lsp
;
112 if (lsp
->segment_list
!= NULL
) {
113 hop
= path_pcep_config_list_path_hops(lsp
->segment_list
);
114 update_origin
= lsp
->segment_list
->protocol_origin
;
115 originator
= XSTRDUP(MTYPE_PCEP
, lsp
->segment_list
->originator
);
117 path
= pcep_new_path();
118 name
= candidate_name(candidate
);
119 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_BEST
)) {
120 status
= status_int_to_ext(policy
->status
);
122 status
= PCEP_LSP_OPERATIONAL_DOWN
;
124 for (uint32_t i
= 0; i
< MAX_METRIC_TYPE
; i
++) {
125 struct path_metric
*path_metric
;
126 struct srte_metric
*srte_metric
= &lsp
->metrics
[i
];
127 if (CHECK_FLAG(srte_metric
->flags
, F_METRIC_IS_DEFINED
)) {
128 path_metric
= pcep_new_metric();
129 path_metric
->next
= metric
;
130 metric
= path_metric
;
131 metric
->type
= i
+ 1;
132 metric
->value
= srte_metric
->value
;
133 metric
->enforce
= CHECK_FLAG(srte_metric
->flags
,
134 F_METRIC_IS_REQUIRED
);
135 metric
->is_bound
= CHECK_FLAG(srte_metric
->flags
,
137 metric
->is_computed
= CHECK_FLAG(srte_metric
->flags
,
138 F_METRIC_IS_COMPUTED
);
141 *path
= (struct path
){
142 .nbkey
= (struct lsp_nb_key
){.color
= policy
->color
,
143 .endpoint
= policy
->endpoint
,
145 candidate
->preference
},
146 .create_origin
= lsp
->protocol_origin
,
147 .update_origin
= update_origin
,
148 .originator
= originator
,
151 .type
= candidate
->type
,
152 .srp_id
= policy
->srp_id
,
154 .binding_sid
= policy
->binding_sid
,
158 .was_created
= false,
159 .was_removed
= false,
160 .is_synching
= false,
161 .is_delegated
= false,
163 .first_metric
= metric
};
165 path
->has_bandwidth
= CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_BANDWIDTH
);
166 if (path
->has_bandwidth
) {
167 path
->enforce_bandwidth
=
168 CHECK_FLAG(lsp
->flags
, F_CANDIDATE_REQUIRED_BANDWIDTH
);
169 path
->bandwidth
= lsp
->bandwidth
;
171 path
->enforce_bandwidth
= true;
175 copy_candidate_objfun_info(candidate
, path
);
176 copy_candidate_affinity_filters(candidate
, path
);
181 void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
184 struct srte_lsp
*lsp
= candidate
->lsp
;
187 if (CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
188 path
->has_pce_objfun
= true;
189 path
->pce_objfun
= lsp
->objfun
;
191 path
->has_pce_objfun
= false;
192 path
->pce_objfun
= OBJFUN_UNDEFINED
;
195 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
196 path
->has_pcc_objfun
= true;
197 path
->pcc_objfun
= candidate
->objfun
;
198 path
->enforce_pcc_objfun
= CHECK_FLAG(
199 candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
202 path
->has_pcc_objfun
= false;
203 path
->pcc_objfun
= OBJFUN_UNDEFINED
;
204 UNSET_FLAG(candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
208 void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
211 bool eany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_EXCLUDE_ANY
);
212 bool iany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ANY
);
213 bool iall
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ALL
);
214 path
->has_affinity_filters
= eany
|| iany
|| iall
;
215 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
216 eany
? candidate
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
219 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
220 iany
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
223 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
224 iall
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
230 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
)
232 struct srte_segment_entry
*segment
;
233 struct path_hop
*hop
= NULL
, *last_hop
= NULL
;
235 RB_FOREACH_REVERSE (segment
, srte_segment_entry_head
,
236 &segment_list
->segments
) {
237 hop
= pcep_new_hop();
238 *hop
= (struct path_hop
){
243 .has_attribs
= false,
244 .sid
= {.mpls
= {.label
= segment
->sid_value
}},
246 segment
->nai_type
!= SRTE_SEGMENT_NAI_TYPE_NONE
,
247 .nai
= {.type
= pcep_nai_type(segment
->nai_type
)}};
248 switch (segment
->nai_type
) {
249 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
250 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
251 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE
:
252 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE
:
253 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM
:
254 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM
:
255 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
256 sizeof(struct ipaddr
));
258 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
259 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
260 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
261 sizeof(struct ipaddr
));
262 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
263 sizeof(struct ipaddr
));
265 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
266 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
267 sizeof(struct ipaddr
));
268 hop
->nai
.local_iface
= segment
->nai_local_iface
;
269 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
270 sizeof(struct ipaddr
));
271 hop
->nai
.remote_iface
= segment
->nai_remote_iface
;
281 int path_pcep_config_initiate_path(struct path
*path
)
283 struct srte_policy
*policy
;
284 struct srte_candidate
*candidate
;
286 if (path
->do_remove
) {
287 zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
289 candidate
= lookup_candidate(&path
->nbkey
);
291 if (!path
->is_delegated
) {
293 "(%s)PCE tried to REMOVE but it's not Delegated!",
297 if (candidate
->type
!= SRTE_CANDIDATE_TYPE_DYNAMIC
) {
299 "(%s)PCE tried to REMOVE but it's not PCE origin!",
304 "(%s)PCE tried to REMOVE found canidate!, let's remove",
306 candidate
->policy
->srp_id
= path
->srp_id
;
307 SET_FLAG(candidate
->policy
->flags
, F_POLICY_DELETED
);
308 SET_FLAG(candidate
->flags
, F_CANDIDATE_DELETED
);
310 zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
314 srte_apply_changes();
316 assert(!IS_IPADDR_NONE(&path
->nbkey
.endpoint
));
318 if (path
->nbkey
.preference
== 0)
319 path
->nbkey
.preference
= INITIATED_CANDIDATE_PREFERENCE
;
321 if (path
->nbkey
.color
== 0)
322 path
->nbkey
.color
= INITIATED_POLICY_COLOR
;
324 candidate
= lookup_candidate(&path
->nbkey
);
326 policy
= srte_policy_add(
327 path
->nbkey
.color
, &path
->nbkey
.endpoint
,
328 SRTE_ORIGIN_PCEP
, path
->originator
);
329 strlcpy(policy
->name
, path
->name
, sizeof(policy
->name
));
330 policy
->binding_sid
= path
->binding_sid
;
331 SET_FLAG(policy
->flags
, F_POLICY_NEW
);
332 candidate
= srte_candidate_add(
333 policy
, path
->nbkey
.preference
,
334 SRTE_ORIGIN_PCEP
, path
->originator
);
335 candidate
->policy
->srp_id
= path
->srp_id
;
336 strlcpy(candidate
->name
, path
->name
,
337 sizeof(candidate
->name
));
338 SET_FLAG(candidate
->flags
, F_CANDIDATE_NEW
);
340 policy
= candidate
->policy
;
341 if ((path
->originator
!= candidate
->originator
)
342 || (path
->originator
!= policy
->originator
)) {
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 already initiated by PCE %s",
349 candidate
->originator
);
352 if ((policy
->protocol_origin
!= SRTE_ORIGIN_PCEP
)
353 || (candidate
->protocol_origin
354 != SRTE_ORIGIN_PCEP
)) {
355 /* There is already an initiated path from
356 * another PCE, show a warning and regect the
359 "PCE %s tried to initiate a path created localy",
364 return path_pcep_config_update_path(path
);
369 int path_pcep_config_update_path(struct path
*path
)
371 assert(path
!= NULL
);
372 assert(path
->nbkey
.preference
!= 0);
373 assert(path
->nbkey
.endpoint
.ipa_type
== IPADDR_V4
);
375 int number_of_sid_clashed
= 0;
376 struct path_hop
*hop
;
377 struct path_metric
*metric
;
379 char segment_list_name_buff
[64 + 1 + 64 + 1 + 11 + 1];
380 char *segment_list_name
= NULL
;
381 struct srte_candidate
*candidate
;
382 struct srte_segment_list
*segment_list
= NULL
;
383 struct srte_segment_entry
*segment
;
385 candidate
= lookup_candidate(&path
->nbkey
);
387 // if there is no candidate to update we are done
391 candidate
->policy
->srp_id
= path
->srp_id
;
392 // first clean up old segment list if present
393 if (candidate
->lsp
->segment_list
) {
394 SET_FLAG(candidate
->lsp
->segment_list
->flags
,
395 F_SEGMENT_LIST_DELETED
);
396 srte_segment_list_del(candidate
->lsp
->segment_list
);
397 candidate
->lsp
->segment_list
= NULL
;
400 if (path
->first_hop
== NULL
)
403 snprintf(segment_list_name_buff
, sizeof(segment_list_name_buff
),
404 "%s-%u", path
->name
, path
->plsp_id
);
405 segment_list_name
= segment_list_name_buff
;
407 segment_list
= srte_segment_list_add(segment_list_name
);
408 segment_list
->protocol_origin
= path
->update_origin
;
409 strlcpy(segment_list
->originator
, path
->originator
,
410 sizeof(segment_list
->originator
));
411 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_NEW
);
412 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
414 for (hop
= path
->first_hop
, index
= 10; hop
!= NULL
;
415 hop
= hop
->next
, index
+= 10) {
416 assert(hop
->has_sid
);
417 assert(hop
->is_mpls
);
419 segment
= srte_segment_entry_add(segment_list
, index
);
421 segment
->sid_value
= (mpls_label_t
)hop
->sid
.mpls
.label
;
422 SET_FLAG(segment
->segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
426 if (srte_segment_entry_set_nai(
427 segment
, srte_nai_type(hop
->nai
.type
),
428 &hop
->nai
.local_addr
, hop
->nai
.local_iface
,
429 &hop
->nai
.remote_addr
, hop
->nai
.remote_iface
, 0, 0)
431 /* TED queries don't match PCE */
432 /* Don't apply srte,zebra changes */
433 number_of_sid_clashed
++;
436 candidate
->lsp
->segment_list
= segment_list
;
437 SET_FLAG(candidate
->flags
, F_CANDIDATE_MODIFIED
);
439 for (metric
= path
->first_metric
; metric
!= NULL
; metric
= metric
->next
)
442 (enum srte_candidate_metric_type
)metric
->type
,
443 metric
->value
, metric
->enforce
, metric
->is_bound
,
444 metric
->is_computed
);
446 if (path
->has_bandwidth
)
447 srte_lsp_set_bandwidth(candidate
->lsp
, path
->bandwidth
,
448 path
->enforce_bandwidth
);
450 if (path
->has_pce_objfun
) {
451 SET_FLAG(candidate
->lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
);
452 candidate
->lsp
->objfun
= path
->pce_objfun
;
455 if (number_of_sid_clashed
)
456 SET_FLAG(segment
->segment_list
->flags
,
457 F_SEGMENT_LIST_SID_CONFLICT
);
459 srte_apply_changes();
464 struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
)
466 struct srte_policy
*policy
= NULL
;
467 policy
= srte_policy_find(key
->color
, &key
->endpoint
);
470 return srte_candidate_find(policy
, key
->preference
);
473 char *candidate_name(struct srte_candidate
*candidate
)
475 if (candidate
->protocol_origin
== SRTE_ORIGIN_PCEP
476 || candidate
->protocol_origin
== SRTE_ORIGIN_BGP
)
477 return asprintfrr(MTYPE_PCEP
, "%s", candidate
->policy
->name
);
479 return asprintfrr(MTYPE_PCEP
, "%s-%s", candidate
->policy
->name
,
483 enum pcep_lsp_operational_status
484 status_int_to_ext(enum srte_policy_status status
)
487 case SRTE_POLICY_STATUS_UP
:
488 return PCEP_LSP_OPERATIONAL_ACTIVE
;
489 case SRTE_POLICY_STATUS_GOING_UP
:
490 return PCEP_LSP_OPERATIONAL_GOING_UP
;
491 case SRTE_POLICY_STATUS_GOING_DOWN
:
492 return PCEP_LSP_OPERATIONAL_GOING_DOWN
;
494 return PCEP_LSP_OPERATIONAL_DOWN
;
498 enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
)
501 case SRTE_SEGMENT_NAI_TYPE_NONE
:
502 return PCEP_SR_SUBOBJ_NAI_ABSENT
;
503 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
504 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
505 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
506 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
507 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
508 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
;
509 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
510 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
;
511 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
512 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
;
513 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES
:
514 return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
;
515 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE
:
516 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
517 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE
:
518 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
519 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM
:
520 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
521 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM
:
522 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
524 return PCEP_SR_SUBOBJ_NAI_UNKNOWN
;
528 enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
)
531 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
532 return SRTE_SEGMENT_NAI_TYPE_NONE
;
533 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
534 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
;
535 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
536 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
;
537 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
538 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
;
539 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
540 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
;
541 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
542 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
;
544 return SRTE_SEGMENT_NAI_TYPE_NONE
;