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 <pcep-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 static int path_pcep_config_lookup_cb(struct thread
*t
)
50 struct path
*path
= THREAD_ARG(t
);
51 struct srte_candidate
*candidate
= lookup_candidate(&path
->nbkey
);
54 if (candidate
== NULL
)
59 if (path
->name
== NULL
)
60 path
->name
= candidate_name(candidate
);
61 if (path
->type
== SRTE_CANDIDATE_TYPE_UNDEFINED
)
62 path
->type
= candidate
->type
;
63 if (path
->create_origin
== SRTE_ORIGIN_UNDEFINED
)
64 path
->create_origin
= candidate
->protocol_origin
;
65 if ((path
->update_origin
== SRTE_ORIGIN_UNDEFINED
)
66 && (lsp
->segment_list
!= NULL
))
67 path
->update_origin
= lsp
->segment_list
->protocol_origin
;
72 void path_pcep_config_lookup(struct path
*path
)
75 * Configuration access is strictly done via the main thread
77 thread_execute(master
, path_pcep_config_lookup_cb
, path
, 0);
80 struct path
*path_pcep_config_get_path(struct lsp_nb_key
*key
)
82 struct srte_candidate
*candidate
= lookup_candidate(key
);
83 if (candidate
== NULL
)
85 return candidate_to_path(candidate
);
88 void path_pcep_config_list_path(path_list_cb_t cb
, void *arg
)
91 struct srte_policy
*policy
;
92 struct srte_candidate
*candidate
;
94 RB_FOREACH (policy
, srte_policy_head
, &srte_policies
) {
95 RB_FOREACH (candidate
, srte_candidate_head
,
96 &policy
->candidate_paths
) {
97 path
= candidate_to_path(candidate
);
104 struct path
*candidate_to_path(struct srte_candidate
*candidate
)
108 struct path_hop
*hop
= NULL
;
109 struct path_metric
*metric
= NULL
;
110 struct srte_policy
*policy
;
111 struct srte_lsp
*lsp
;
112 enum pcep_lsp_operational_status status
;
113 enum srte_protocol_origin update_origin
= 0;
114 char *originator
= NULL
;
116 policy
= candidate
->policy
;
117 lsp
= candidate
->lsp
;
119 if (lsp
->segment_list
!= NULL
) {
120 hop
= path_pcep_config_list_path_hops(lsp
->segment_list
);
121 update_origin
= lsp
->segment_list
->protocol_origin
;
122 originator
= XSTRDUP(MTYPE_PCEP
, lsp
->segment_list
->originator
);
124 path
= pcep_new_path();
125 name
= candidate_name(candidate
);
126 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_BEST
)) {
127 status
= status_int_to_ext(policy
->status
);
129 status
= PCEP_LSP_OPERATIONAL_DOWN
;
131 for (uint32_t i
= 0; i
< MAX_METRIC_TYPE
; i
++) {
132 struct path_metric
*path_metric
;
133 struct srte_metric
*srte_metric
= &lsp
->metrics
[i
];
134 if (CHECK_FLAG(srte_metric
->flags
, F_METRIC_IS_DEFINED
)) {
135 path_metric
= pcep_new_metric();
136 path_metric
->next
= metric
;
137 metric
= path_metric
;
138 metric
->type
= i
+ 1;
139 metric
->value
= srte_metric
->value
;
140 metric
->enforce
= CHECK_FLAG(srte_metric
->flags
,
141 F_METRIC_IS_REQUIRED
);
142 metric
->is_bound
= CHECK_FLAG(srte_metric
->flags
,
144 metric
->is_computed
= CHECK_FLAG(srte_metric
->flags
,
145 F_METRIC_IS_COMPUTED
);
148 *path
= (struct path
){
149 .nbkey
= (struct lsp_nb_key
){.color
= policy
->color
,
150 .endpoint
= policy
->endpoint
,
152 candidate
->preference
},
153 .create_origin
= lsp
->protocol_origin
,
154 .update_origin
= update_origin
,
155 .originator
= originator
,
158 .type
= candidate
->type
,
161 .binding_sid
= policy
->binding_sid
,
165 .was_created
= false,
166 .was_removed
= false,
167 .is_synching
= false,
168 .is_delegated
= false,
170 .first_metric
= metric
};
172 path
->has_bandwidth
= CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_BANDWIDTH
);
173 if (path
->has_bandwidth
) {
174 path
->enforce_bandwidth
=
175 CHECK_FLAG(lsp
->flags
, F_CANDIDATE_REQUIRED_BANDWIDTH
);
176 path
->bandwidth
= lsp
->bandwidth
;
178 path
->enforce_bandwidth
= true;
182 copy_candidate_objfun_info(candidate
, path
);
183 copy_candidate_affinity_filters(candidate
, path
);
188 void copy_candidate_objfun_info(struct srte_candidate
*candidate
,
191 struct srte_lsp
*lsp
= candidate
->lsp
;
194 if (CHECK_FLAG(lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
195 path
->has_pce_objfun
= true;
196 path
->pce_objfun
= lsp
->objfun
;
198 path
->has_pce_objfun
= false;
199 path
->pce_objfun
= OBJFUN_UNDEFINED
;
202 if (CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_OBJFUN
)) {
203 path
->has_pcc_objfun
= true;
204 path
->pcc_objfun
= candidate
->objfun
;
205 path
->enforce_pcc_objfun
= CHECK_FLAG(
206 candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
209 path
->has_pcc_objfun
= false;
210 path
->pcc_objfun
= OBJFUN_UNDEFINED
;
211 UNSET_FLAG(candidate
->flags
, F_CANDIDATE_REQUIRED_OBJFUN
);
215 void copy_candidate_affinity_filters(struct srte_candidate
*candidate
,
218 bool eany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_EXCLUDE_ANY
);
219 bool iany
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ANY
);
220 bool iall
= CHECK_FLAG(candidate
->flags
, F_CANDIDATE_HAS_INCLUDE_ALL
);
221 path
->has_affinity_filters
= eany
|| iany
|| iall
;
222 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
223 eany
? candidate
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
226 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
227 iany
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
230 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
231 iall
? candidate
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
237 path_pcep_config_list_path_hops(struct srte_segment_list
*segment_list
)
239 struct srte_segment_entry
*segment
;
240 struct path_hop
*hop
= NULL
, *last_hop
= NULL
;
242 RB_FOREACH_REVERSE (segment
, srte_segment_entry_head
,
243 &segment_list
->segments
) {
244 hop
= pcep_new_hop();
245 *hop
= (struct path_hop
){
250 .has_attribs
= false,
251 .sid
= {.mpls
= {.label
= segment
->sid_value
}},
253 segment
->nai_type
!= SRTE_SEGMENT_NAI_TYPE_NONE
,
254 .nai
= {.type
= pcep_nai_type(segment
->nai_type
)}};
255 switch (segment
->nai_type
) {
256 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
257 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
258 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
259 sizeof(struct ipaddr
));
261 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
262 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
263 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
264 sizeof(struct ipaddr
));
265 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
266 sizeof(struct ipaddr
));
268 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
269 memcpy(&hop
->nai
.local_addr
, &segment
->nai_local_addr
,
270 sizeof(struct ipaddr
));
271 hop
->nai
.local_iface
= segment
->nai_local_iface
;
272 memcpy(&hop
->nai
.remote_addr
, &segment
->nai_remote_addr
,
273 sizeof(struct ipaddr
));
274 hop
->nai
.remote_iface
= segment
->nai_remote_iface
;
284 int path_pcep_config_update_path(struct path
*path
)
286 assert(path
!= NULL
);
287 assert(path
->nbkey
.preference
!= 0);
288 assert(path
->nbkey
.endpoint
.ipa_type
== IPADDR_V4
);
290 struct path_hop
*hop
;
291 struct path_metric
*metric
;
293 char segment_list_name_buff
[64 + 1 + 64 + 1 + 11 + 1];
294 char *segment_list_name
= NULL
;
295 struct srte_candidate
*candidate
;
296 struct srte_segment_list
*segment_list
= NULL
;
297 struct srte_segment_entry
*segment
;
299 candidate
= lookup_candidate(&path
->nbkey
);
301 // if there is no candidate to update we are done
305 // first clean up old segment list if present
306 if (candidate
->lsp
->segment_list
) {
307 SET_FLAG(candidate
->lsp
->segment_list
->flags
,
308 F_SEGMENT_LIST_DELETED
);
309 candidate
->lsp
->segment_list
= NULL
;
312 if (path
->first_hop
!= NULL
) {
313 snprintf(segment_list_name_buff
, sizeof(segment_list_name_buff
),
314 "%s-%u", path
->name
, path
->plsp_id
);
315 segment_list_name
= segment_list_name_buff
;
317 segment_list
= srte_segment_list_add(segment_list_name
);
318 segment_list
->protocol_origin
= path
->update_origin
;
319 strlcpy(segment_list
->originator
, path
->originator
,
320 sizeof(segment_list
->originator
));
321 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_NEW
);
322 SET_FLAG(segment_list
->flags
, F_SEGMENT_LIST_MODIFIED
);
324 for (hop
= path
->first_hop
, index
= 10; hop
!= NULL
;
325 hop
= hop
->next
, index
+= 10) {
326 assert(hop
->has_sid
);
327 assert(hop
->is_mpls
);
329 segment
= srte_segment_entry_add(segment_list
, index
);
331 segment
->sid_value
= (mpls_label_t
)hop
->sid
.mpls
.label
;
332 SET_FLAG(segment
->segment_list
->flags
,
333 F_SEGMENT_LIST_MODIFIED
);
336 srte_segment_entry_set_nai(
337 segment
, srte_nai_type(hop
->nai
.type
),
338 &hop
->nai
.local_addr
,
339 hop
->nai
.local_iface
,
340 &hop
->nai
.remote_addr
,
341 hop
->nai
.remote_iface
);
345 candidate
->lsp
->segment_list
= segment_list
;
346 SET_FLAG(candidate
->flags
, F_CANDIDATE_MODIFIED
);
348 for (metric
= path
->first_metric
; metric
!= NULL
; metric
= metric
->next
)
349 srte_lsp_set_metric(candidate
->lsp
, metric
->type
, metric
->value
,
350 metric
->enforce
, metric
->is_bound
,
351 metric
->is_computed
);
353 if (path
->has_bandwidth
)
354 srte_lsp_set_bandwidth(candidate
->lsp
, path
->bandwidth
,
355 path
->enforce_bandwidth
);
357 if (path
->has_pce_objfun
) {
358 SET_FLAG(candidate
->lsp
->flags
, F_CANDIDATE_HAS_OBJFUN
);
359 candidate
->lsp
->objfun
= path
->pce_objfun
;
362 srte_apply_changes();
367 struct srte_candidate
*lookup_candidate(struct lsp_nb_key
*key
)
369 struct srte_policy
*policy
= NULL
;
370 policy
= srte_policy_find(key
->color
, &key
->endpoint
);
373 return srte_candidate_find(policy
, key
->preference
);
376 char *candidate_name(struct srte_candidate
*candidate
)
378 return asprintfrr(MTYPE_PCEP
, "%s-%s", candidate
->policy
->name
,
382 enum pcep_lsp_operational_status
383 status_int_to_ext(enum srte_policy_status status
)
386 case SRTE_POLICY_STATUS_UP
:
387 return PCEP_LSP_OPERATIONAL_ACTIVE
;
388 case SRTE_POLICY_STATUS_GOING_UP
:
389 return PCEP_LSP_OPERATIONAL_GOING_UP
;
390 case SRTE_POLICY_STATUS_GOING_DOWN
:
391 return PCEP_LSP_OPERATIONAL_GOING_DOWN
;
393 return PCEP_LSP_OPERATIONAL_DOWN
;
397 enum pcep_sr_subobj_nai
pcep_nai_type(enum srte_segment_nai_type type
)
400 case SRTE_SEGMENT_NAI_TYPE_NONE
:
401 return PCEP_SR_SUBOBJ_NAI_ABSENT
;
402 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
:
403 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE
;
404 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
:
405 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE
;
406 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
:
407 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
;
408 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
:
409 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
;
410 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
:
411 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
;
413 return PCEP_SR_SUBOBJ_NAI_UNKNOWN
;
417 enum srte_segment_nai_type
srte_nai_type(enum pcep_sr_subobj_nai type
)
420 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
421 return SRTE_SEGMENT_NAI_TYPE_NONE
;
422 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
423 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE
;
424 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
425 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE
;
426 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
427 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY
;
428 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
429 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY
;
430 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
431 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY
;
433 return SRTE_SEGMENT_NAI_TYPE_NONE
;