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
37 static void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
39 static void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
41 static struct path_hop
*
42 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
);
43 static struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
);
44 static char *candidate_name(struct srte_candidate
*candidate
);
45 static enum pcep_lsp_operational_status
46 status_int_to_ext(enum srte_policy_status status
);
47 static enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
);
48 static enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
);
50 void path_pcep_refine_path(struct path
*path
)
52 struct srte_candidate
*candidate
= lookup_candidate(&path
->nbkey
);
55 if (candidate
== NULL
)
60 if (path
->name
== NULL
)
61 path
->name
= candidate_name(candidate
);
62 if (path
->type
== SRTE_CANDIDATE_TYPE_UNDEFINED
)
63 path
->type
= candidate
->type
;
64 if (path
->create_origin
== SRTE_ORIGIN_UNDEFINED
)
65 path
->create_origin
= candidate
->protocol_origin
;
66 if ((path
->update_origin
== SRTE_ORIGIN_UNDEFINED
)
67 && (lsp
->segment_list
!= NULL
))
68 path
->update_origin
= lsp
->segment_list
->protocol_origin
;
71 struct path
*path_pcep_config_get_path(struct lsp_nb_key
*key
)
73 struct srte_candidate
*candidate
= lookup_candidate(key
);
74 if (candidate
== NULL
)
76 return candidate_to_path(candidate
);
79 void path_pcep_config_list_path(path_list_cb_t cb
, void *arg
)
82 struct srte_policy
*policy
;
83 struct srte_candidate
*candidate
;
85 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
86 RB_FOREACH (candidate
, srte_candidate_head
,
87 &policy
->candidate_paths
) {
88 path
= candidate_to_path(candidate
);
95 struct path
*candidate_to_path(struct srte_candidate
*candidate
)
99 struct path_hop
*hop
= NULL
;
100 struct path_metric
*metric
= NULL
;
101 struct srte_policy
*policy
;
102 struct srte_lsp
*lsp
;
103 enum pcep_lsp_operational_status status
;
104 enum srte_protocol_origin update_origin
= 0;
105 char *originator
= NULL
;
107 policy
= candidate
->policy
;
108 lsp
= candidate
->lsp
;
110 if (lsp
->segment_list
!= NULL
) {
111 hop
= path_pcep_config_list_path_hops(lsp
->segment_list
);
112 update_origin
= lsp
->segment_list
->protocol_origin
;
113 originator
= XSTRDUP(MTYPE_PCEP
, lsp
->segment_list
->originator
);
115 path
= pcep_new_path();
116 name
= candidate_name(candidate
);
117 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_BEST
)) {
118 status
= status_int_to_ext(policy
->status
);
120 status
= PCEP_LSP_OPERATIONAL_DOWN
;
122 for (uint32_t i
= 0; i
< MAX_METRIC_TYPE
; i
++) {
123 struct path_metric
*path_metric
;
124 struct srte_metric
*srte_metric
= &lsp
->metrics
[i
];
125 if (CHECK_FLAG(srte_metric
->flags
, F_METRIC_IS_DEFINED
)) {
126 path_metric
= pcep_new_metric();
127 path_metric
->next
= metric
;
128 metric
= path_metric
;
129 metric
->type
= i
+ 1;
130 metric
->value
= srte_metric
->value
;
131 metric
->enforce
= CHECK_FLAG(srte_metric
->flags
,
132 F_METRIC_IS_REQUIRED
);
133 metric
->is_bound
= CHECK_FLAG(srte_metric
->flags
,
135 metric
->is_computed
= CHECK_FLAG(srte_metric
->flags
,
136 F_METRIC_IS_COMPUTED
);
139 *path
= (struct path
){
140 .nbkey
= (struct lsp_nb_key
){.color
= policy
->color
,
141 .endpoint
= policy
->endpoint
,
143 candidate
->preference
},
144 .create_origin
= lsp
->protocol_origin
,
145 .update_origin
= update_origin
,
146 .originator
= originator
,
149 .type
= candidate
->type
,
152 .binding_sid
= policy
->binding_sid
,
156 .was_created
= false,
157 .was_removed
= false,
158 .is_synching
= false,
159 .is_delegated
= false,
161 .first_metric
= metric
};
163 path
->has_bandwidth
= CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_BANDWIDTH
);
164 if (path
->has_bandwidth
) {
165 path
->enforce_bandwidth
=
166 CHECK_FLAG(lsp
->flags
, F_CANDIDATE_REQUIRED_BANDWIDTH
);
167 path
->bandwidth
= lsp
->bandwidth
;
169 path
->enforce_bandwidth
= true;
173 copy_candidate_objfun_info(candidate
, path
);
174 copy_candidate_affinity_filters(candidate
, path
);
179 void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
182 struct srte_lsp
*lsp
= candidate
->lsp
;
185 if (CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
186 path
->has_pce_objfun
= true;
187 path
->pce_objfun
= lsp
->objfun
;
189 path
->has_pce_objfun
= false;
190 path
->pce_objfun
= OBJFUN_UNDEFINED
;
193 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
194 path
->has_pcc_objfun
= true;
195 path
->pcc_objfun
= candidate
->objfun
;
196 path
->enforce_pcc_objfun
= CHECK_FLAG(
197 candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
200 path
->has_pcc_objfun
= false;
201 path
->pcc_objfun
= OBJFUN_UNDEFINED
;
202 UNSET_FLAG(candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
206 void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
209 bool eany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_EXCLUDE_ANY
);
210 bool iany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ANY
);
211 bool iall
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ALL
);
212 path
->has_affinity_filters
= eany
|| iany
|| iall
;
213 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
214 eany
? candidate
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
217 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
218 iany
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
221 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
222 iall
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
228 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
)
230 struct srte_segment_entry
*segment
;
231 struct path_hop
*hop
= NULL
, *last_hop
= NULL
;
233 RB_FOREACH_REVERSE (segment
, srte_segment_entry_head
,
234 &segment_list
->segments
) {
235 hop
= pcep_new_hop();
236 *hop
= (struct path_hop
){
241 .has_attribs
= false,
242 .sid
= {.mpls
= {.label
= segment
->sid_value
}},
244 segment
->nai_type
!= SRTE_SEGMENT_NAI_TYPE_NONE
,
245 .nai
= {.type
= pcep_nai_type(segment
->nai_type
)}};
246 switch (segment
->nai_type
) {
247 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
248 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
249 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
250 sizeof(struct ipaddr
));
252 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
253 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
254 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
255 sizeof(struct ipaddr
));
256 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
257 sizeof(struct ipaddr
));
259 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
260 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
261 sizeof(struct ipaddr
));
262 hop
->nai
.local_iface
= segment
->nai_local_iface
;
263 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
264 sizeof(struct ipaddr
));
265 hop
->nai
.remote_iface
= segment
->nai_remote_iface
;
275 int path_pcep_config_update_path(struct path
*path
)
277 assert(path
!= NULL
);
278 assert(path
->nbkey
.preference
!= 0);
279 assert(path
->nbkey
.endpoint
.ipa_type
== IPADDR_V4
);
281 struct path_hop
*hop
;
282 struct path_metric
*metric
;
284 char segment_list_name_buff
[64 + 1 + 64 + 1 + 11 + 1];
285 char *segment_list_name
= NULL
;
286 struct srte_candidate
*candidate
;
287 struct srte_segment_list
*segment_list
= NULL
;
288 struct srte_segment_entry
*segment
;
290 candidate
= lookup_candidate(&path
->nbkey
);
292 // if there is no candidate to update we are done
296 // first clean up old segment list if present
297 if (candidate
->lsp
->segment_list
) {
298 SET_FLAG(candidate
->lsp
->segment_list
->flags
,
299 F_SEGMENT_LIST_DELETED
);
300 candidate
->lsp
->segment_list
= NULL
;
303 if (path
->first_hop
!= NULL
) {
304 snprintf(segment_list_name_buff
, sizeof(segment_list_name_buff
),
305 "%s-%u", path
->name
, path
->plsp_id
);
306 segment_list_name
= segment_list_name_buff
;
308 segment_list
= srte_segment_list_add(segment_list_name
);
309 segment_list
->protocol_origin
= path
->update_origin
;
310 strlcpy(segment_list
->originator
, path
->originator
,
311 sizeof(segment_list
->originator
));
312 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_NEW
);
313 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
315 for (hop
= path
->first_hop
, index
= 10; hop
!= NULL
;
316 hop
= hop
->next
, index
+= 10) {
317 assert(hop
->has_sid
);
318 assert(hop
->is_mpls
);
320 segment
= srte_segment_entry_add(segment_list
, index
);
322 segment
->sid_value
= (mpls_label_t
)hop
->sid
.mpls
.label
;
323 SET_FLAG(segment
->segment_list
->flags
,
324 F_SEGMENT_LIST_MODIFIED
);
327 srte_segment_entry_set_nai(
328 segment
, srte_nai_type(hop
->nai
.type
),
329 &hop
->nai
.local_addr
,
330 hop
->nai
.local_iface
,
331 &hop
->nai
.remote_addr
,
332 hop
->nai
.remote_iface
);
336 candidate
->lsp
->segment_list
= segment_list
;
337 SET_FLAG(candidate
->flags
, F_CANDIDATE_MODIFIED
);
339 for (metric
= path
->first_metric
; metric
!= NULL
; metric
= metric
->next
)
342 (enum srte_candidate_metric_type
)metric
->type
,
343 metric
->value
, metric
->enforce
, metric
->is_bound
,
344 metric
->is_computed
);
346 if (path
->has_bandwidth
)
347 srte_lsp_set_bandwidth(candidate
->lsp
, path
->bandwidth
,
348 path
->enforce_bandwidth
);
350 if (path
->has_pce_objfun
) {
351 SET_FLAG(candidate
->lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
);
352 candidate
->lsp
->objfun
= path
->pce_objfun
;
355 srte_apply_changes();
360 struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
)
362 struct srte_policy
*policy
= NULL
;
363 policy
= srte_policy_find(key
->color
, &key
->endpoint
);
366 return srte_candidate_find(policy
, key
->preference
);
369 char *candidate_name(struct srte_candidate
*candidate
)
371 return asprintfrr(MTYPE_PCEP
, "%s-%s", candidate
->policy
->name
,
375 enum pcep_lsp_operational_status
376 status_int_to_ext(enum srte_policy_status status
)
379 case SRTE_POLICY_STATUS_UP
:
380 return PCEP_LSP_OPERATIONAL_ACTIVE
;
381 case SRTE_POLICY_STATUS_GOING_UP
:
382 return PCEP_LSP_OPERATIONAL_GOING_UP
;
383 case SRTE_POLICY_STATUS_GOING_DOWN
:
384 return PCEP_LSP_OPERATIONAL_GOING_DOWN
;
386 return PCEP_LSP_OPERATIONAL_DOWN
;
390 enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
)
393 case SRTE_SEGMENT_NAI_TYPE_NONE
:
394 return PCEP_SR_SUBOBJ_NAI_ABSENT
;
395 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
396 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
397 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
398 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
399 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
400 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
;
401 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
402 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
;
403 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
404 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
;
406 return PCEP_SR_SUBOBJ_NAI_UNKNOWN
;
410 enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
)
413 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
414 return SRTE_SEGMENT_NAI_TYPE_NONE
;
415 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
416 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
;
417 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
418 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
;
419 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
420 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
;
421 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
422 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
;
423 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
424 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
;
426 return SRTE_SEGMENT_NAI_TYPE_NONE
;