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
19 #include <northbound.h>
22 #include "pceplib/pcep_msg_objects.h"
23 #include "pathd/pathd.h"
24 #include "pathd/path_pcep.h"
25 #include "pathd/path_pcep_config.h"
26 #include "pathd/path_pcep_debug.h"
30 #define MAX_FLOAT_LEN 22
31 #define INETADDR4_MAXLEN 16
32 #define INETADDR6_MAXLEN 40
35 static void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
37 static void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
39 static struct path_hop
*
40 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
);
41 static struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
);
42 static char *candidate_name(struct srte_candidate
*candidate
);
43 static enum pcep_lsp_operational_status
44 status_int_to_ext(enum srte_policy_status status
);
45 static enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
);
46 static enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
);
48 void path_pcep_refine_path(struct path
*path
)
50 struct srte_candidate
*candidate
= lookup_candidate(&path
->nbkey
);
53 if (candidate
== NULL
)
58 if (path
->name
== NULL
)
59 path
->name
= candidate_name(candidate
);
60 if (path
->type
== SRTE_CANDIDATE_TYPE_UNDEFINED
)
61 path
->type
= candidate
->type
;
62 if (path
->create_origin
== SRTE_ORIGIN_UNDEFINED
)
63 path
->create_origin
= candidate
->protocol_origin
;
64 if ((path
->update_origin
== SRTE_ORIGIN_UNDEFINED
)
65 && (lsp
->segment_list
!= NULL
))
66 path
->update_origin
= lsp
->segment_list
->protocol_origin
;
69 struct path
*path_pcep_config_get_path(struct lsp_nb_key
*key
)
71 struct srte_candidate
*candidate
= lookup_candidate(key
);
72 if (candidate
== NULL
)
74 return candidate_to_path(candidate
);
77 void path_pcep_config_list_path(path_list_cb_t cb
, void *arg
)
80 struct srte_policy
*policy
;
81 struct srte_candidate
*candidate
;
83 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
84 RB_FOREACH (candidate
, srte_candidate_head
,
85 &policy
->candidate_paths
) {
86 path
= candidate_to_path(candidate
);
93 struct path
*candidate_to_path(struct srte_candidate
*candidate
)
97 struct path_hop
*hop
= NULL
;
98 struct path_metric
*metric
= NULL
;
99 struct srte_policy
*policy
;
100 struct srte_lsp
*lsp
;
101 enum pcep_lsp_operational_status status
;
102 enum srte_protocol_origin update_origin
= 0;
103 char *originator
= NULL
;
105 policy
= candidate
->policy
;
106 lsp
= candidate
->lsp
;
108 if (lsp
->segment_list
!= NULL
) {
109 hop
= path_pcep_config_list_path_hops(lsp
->segment_list
);
110 update_origin
= lsp
->segment_list
->protocol_origin
;
111 originator
= XSTRDUP(MTYPE_PCEP
, lsp
->segment_list
->originator
);
113 path
= pcep_new_path();
114 name
= candidate_name(candidate
);
115 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_BEST
)) {
116 status
= status_int_to_ext(policy
->status
);
118 status
= PCEP_LSP_OPERATIONAL_DOWN
;
120 for (uint32_t i
= 0; i
< MAX_METRIC_TYPE
; i
++) {
121 struct path_metric
*path_metric
;
122 struct srte_metric
*srte_metric
= &lsp
->metrics
[i
];
123 if (CHECK_FLAG(srte_metric
->flags
, F_METRIC_IS_DEFINED
)) {
124 path_metric
= pcep_new_metric();
125 path_metric
->next
= metric
;
126 metric
= path_metric
;
127 metric
->type
= i
+ 1;
128 metric
->value
= srte_metric
->value
;
129 metric
->enforce
= CHECK_FLAG(srte_metric
->flags
,
130 F_METRIC_IS_REQUIRED
);
131 metric
->is_bound
= CHECK_FLAG(srte_metric
->flags
,
133 metric
->is_computed
= CHECK_FLAG(srte_metric
->flags
,
134 F_METRIC_IS_COMPUTED
);
137 *path
= (struct path
){
138 .nbkey
= (struct lsp_nb_key
){.color
= policy
->color
,
139 .endpoint
= policy
->endpoint
,
141 candidate
->preference
},
142 .create_origin
= lsp
->protocol_origin
,
143 .update_origin
= update_origin
,
144 .originator
= originator
,
147 .type
= candidate
->type
,
150 .binding_sid
= policy
->binding_sid
,
154 .was_created
= false,
155 .was_removed
= false,
156 .is_synching
= false,
157 .is_delegated
= false,
159 .first_metric
= metric
};
161 path
->has_bandwidth
= CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_BANDWIDTH
);
162 if (path
->has_bandwidth
) {
163 path
->enforce_bandwidth
=
164 CHECK_FLAG(lsp
->flags
, F_CANDIDATE_REQUIRED_BANDWIDTH
);
165 path
->bandwidth
= lsp
->bandwidth
;
167 path
->enforce_bandwidth
= true;
171 copy_candidate_objfun_info(candidate
, path
);
172 copy_candidate_affinity_filters(candidate
, path
);
177 void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
180 struct srte_lsp
*lsp
= candidate
->lsp
;
183 if (CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
184 path
->has_pce_objfun
= true;
185 path
->pce_objfun
= lsp
->objfun
;
187 path
->has_pce_objfun
= false;
188 path
->pce_objfun
= OBJFUN_UNDEFINED
;
191 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
192 path
->has_pcc_objfun
= true;
193 path
->pcc_objfun
= candidate
->objfun
;
194 path
->enforce_pcc_objfun
= CHECK_FLAG(
195 candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
198 path
->has_pcc_objfun
= false;
199 path
->pcc_objfun
= OBJFUN_UNDEFINED
;
200 UNSET_FLAG(candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
204 void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
207 bool eany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_EXCLUDE_ANY
);
208 bool iany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ANY
);
209 bool iall
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ALL
);
210 path
->has_affinity_filters
= eany
|| iany
|| iall
;
211 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
212 eany
? candidate
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
215 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
216 iany
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
219 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
220 iall
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
226 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
)
228 struct srte_segment_entry
*segment
;
229 struct path_hop
*hop
= NULL
, *last_hop
= NULL
;
231 RB_FOREACH_REVERSE (segment
, srte_segment_entry_head
,
232 &segment_list
->segments
) {
233 hop
= pcep_new_hop();
234 *hop
= (struct path_hop
){
239 .has_attribs
= false,
240 .sid
= {.mpls
= {.label
= segment
->sid_value
}},
242 segment
->nai_type
!= SRTE_SEGMENT_NAI_TYPE_NONE
,
243 .nai
= {.type
= pcep_nai_type(segment
->nai_type
)}};
244 switch (segment
->nai_type
) {
245 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
246 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
247 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
248 sizeof(struct ipaddr
));
250 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
251 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
252 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
253 sizeof(struct ipaddr
));
254 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
255 sizeof(struct ipaddr
));
257 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
258 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
259 sizeof(struct ipaddr
));
260 hop
->nai
.local_iface
= segment
->nai_local_iface
;
261 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
262 sizeof(struct ipaddr
));
263 hop
->nai
.remote_iface
= segment
->nai_remote_iface
;
273 int path_pcep_config_update_path(struct path
*path
)
275 assert(path
!= NULL
);
276 assert(path
->nbkey
.preference
!= 0);
277 assert(path
->nbkey
.endpoint
.ipa_type
== IPADDR_V4
);
279 struct path_hop
*hop
;
280 struct path_metric
*metric
;
282 char segment_list_name_buff
[64 + 1 + 64 + 1 + 11 + 1];
283 char *segment_list_name
= NULL
;
284 struct srte_candidate
*candidate
;
285 struct srte_segment_list
*segment_list
= NULL
;
286 struct srte_segment_entry
*segment
;
288 candidate
= lookup_candidate(&path
->nbkey
);
290 // if there is no candidate to update we are done
294 // first clean up old segment list if present
295 if (candidate
->lsp
->segment_list
) {
296 SET_FLAG(candidate
->lsp
->segment_list
->flags
,
297 F_SEGMENT_LIST_DELETED
);
298 candidate
->lsp
->segment_list
= NULL
;
301 if (path
->first_hop
!= NULL
) {
302 snprintf(segment_list_name_buff
, sizeof(segment_list_name_buff
),
303 "%s-%u", path
->name
, path
->plsp_id
);
304 segment_list_name
= segment_list_name_buff
;
306 segment_list
= srte_segment_list_add(segment_list_name
);
307 segment_list
->protocol_origin
= path
->update_origin
;
308 strlcpy(segment_list
->originator
, path
->originator
,
309 sizeof(segment_list
->originator
));
310 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_NEW
);
311 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
313 for (hop
= path
->first_hop
, index
= 10; hop
!= NULL
;
314 hop
= hop
->next
, index
+= 10) {
315 assert(hop
->has_sid
);
316 assert(hop
->is_mpls
);
318 segment
= srte_segment_entry_add(segment_list
, index
);
320 segment
->sid_value
= (mpls_label_t
)hop
->sid
.mpls
.label
;
321 SET_FLAG(segment
->segment_list
->flags
,
322 F_SEGMENT_LIST_MODIFIED
);
325 srte_segment_entry_set_nai(
326 segment
, srte_nai_type(hop
->nai
.type
),
327 &hop
->nai
.local_addr
,
328 hop
->nai
.local_iface
,
329 &hop
->nai
.remote_addr
,
330 hop
->nai
.remote_iface
);
334 candidate
->lsp
->segment_list
= segment_list
;
335 SET_FLAG(candidate
->flags
, F_CANDIDATE_MODIFIED
);
337 for (metric
= path
->first_metric
; metric
!= NULL
; metric
= metric
->next
)
340 (enum srte_candidate_metric_type
)metric
->type
,
341 metric
->value
, metric
->enforce
, metric
->is_bound
,
342 metric
->is_computed
);
344 if (path
->has_bandwidth
)
345 srte_lsp_set_bandwidth(candidate
->lsp
, path
->bandwidth
,
346 path
->enforce_bandwidth
);
348 if (path
->has_pce_objfun
) {
349 SET_FLAG(candidate
->lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
);
350 candidate
->lsp
->objfun
= path
->pce_objfun
;
353 srte_apply_changes();
358 struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
)
360 struct srte_policy
*policy
= NULL
;
361 policy
= srte_policy_find(key
->color
, &key
->endpoint
);
364 return srte_candidate_find(policy
, key
->preference
);
367 char *candidate_name(struct srte_candidate
*candidate
)
369 return asprintfrr(MTYPE_PCEP
, "%s-%s", candidate
->policy
->name
,
373 enum pcep_lsp_operational_status
374 status_int_to_ext(enum srte_policy_status status
)
377 case SRTE_POLICY_STATUS_UP
:
378 return PCEP_LSP_OPERATIONAL_ACTIVE
;
379 case SRTE_POLICY_STATUS_GOING_UP
:
380 return PCEP_LSP_OPERATIONAL_GOING_UP
;
381 case SRTE_POLICY_STATUS_GOING_DOWN
:
382 return PCEP_LSP_OPERATIONAL_GOING_DOWN
;
384 return PCEP_LSP_OPERATIONAL_DOWN
;
388 enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
)
391 case SRTE_SEGMENT_NAI_TYPE_NONE
:
392 return PCEP_SR_SUBOBJ_NAI_ABSENT
;
393 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
394 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
395 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
396 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
397 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
398 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
;
399 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
400 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
;
401 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
402 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
;
404 return PCEP_SR_SUBOBJ_NAI_UNKNOWN
;
408 enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
)
411 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
412 return SRTE_SEGMENT_NAI_TYPE_NONE
;
413 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
414 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
;
415 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
416 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
;
417 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
418 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
;
419 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
420 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
;
421 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
422 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
;
424 return SRTE_SEGMENT_NAI_TYPE_NONE
;