1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
11 #include "pceplib/pcep_utils_counters.h"
12 #include "pceplib/pcep_timers.h"
13 #include "pathd/path_errors.h"
14 #include "pathd/path_pcep.h"
15 #include "pathd/path_pcep_lib.h"
16 #include "pathd/path_pcep_debug.h"
18 DEFINE_MTYPE_STATIC(PATHD
, PCEPLIB_INFRA
, "PCEPlib Infrastructure");
19 DEFINE_MTYPE_STATIC(PATHD
, PCEPLIB_MESSAGES
, "PCEPlib PCEP Messages");
21 #define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
22 #define DEFAULT_LSAP_SETUP_PRIO 4
23 #define DEFAULT_LSAP_HOLDING_PRIO 4
24 #define DEFAULT_LSAP_LOCAL_PRETECTION false
25 #define MAX_PATH_NAME_SIZE 255
27 /* pceplib logging callback */
28 static int pceplib_logging_cb(int level
, const char *fmt
, va_list args
)
31 /* Socket callbacks */
32 static int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
34 static int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
36 static void pcep_lib_socket_read_ready(struct thread
*thread
);
37 static void pcep_lib_socket_write_ready(struct thread
*thread
);
39 /* pceplib pcep_event callbacks */
40 static void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
);
42 /* pceplib pthread creation callback */
43 static int pcep_lib_pthread_create_cb(pthread_t
*pthread_id
,
44 const pthread_attr_t
*attr
,
45 void *(*start_routine
)(void *),
46 void *data
, const char *thread_name
);
47 void *pcep_lib_pthread_start_passthrough(void *data
);
48 int pcep_lib_pthread_stop_cb(struct frr_pthread
*, void **);
50 /* Internal functions */
51 static double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
53 static void pcep_lib_format_constraints(struct path
*path
,
54 double_linked_list
*objs
);
55 static void pcep_lib_parse_open(struct pcep_caps
*caps
,
56 struct pcep_object_open
*open
);
58 pcep_lib_parse_open_pce_capability(struct pcep_caps
*caps
,
59 struct pcep_object_tlv_header
*tlv_header
);
61 pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
62 struct pcep_object_tlv_header
*tlv_header
);
63 static void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
);
64 static void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
);
65 static void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
);
66 static void pcep_lib_parse_lspa(struct path
*path
,
67 struct pcep_object_lspa
*lspa
);
68 static void pcep_lib_parse_lsp_symbolic_name(
69 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
);
70 static void pcep_lib_parse_metric(struct path
*path
,
71 struct pcep_object_metric
*obj
);
73 pcep_lib_parse_endpoints_ipv4(struct path
*path
,
74 struct pcep_object_endpoints_ipv4
*obj
);
76 pcep_lib_parse_endpoints_ipv6(struct path
*path
,
77 struct pcep_object_endpoints_ipv6
*obj
);
78 static void pcep_lib_parse_vendor_info(struct path
*path
,
79 struct pcep_object_vendor_info
*obj
);
80 static void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
);
81 static struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
82 struct pcep_ro_subobj_sr
*sr
);
83 static struct counters_group
*copy_counter_group(struct counters_group
*from
);
84 static struct counters_subgroup
*
85 copy_counter_subgroup(struct counters_subgroup
*from
);
86 static struct counter
*copy_counter(struct counter
*from
);
87 static void free_counter_group(struct counters_group
*group
);
88 static void free_counter_subgroup(struct counters_subgroup
*subgroup
);
89 static void free_counter(struct counter
*counter
);
91 struct pcep_lib_pthread_passthrough_data
{
92 void *(*start_routine
)(void *data
);
96 /* ------------ API Functions ------------ */
98 int pcep_lib_initialize(struct frr_pthread
*fpt
)
100 PCEP_DEBUG("Initializing pceplib");
102 /* Register pceplib logging callback */
103 register_logger(pceplib_logging_cb
);
105 /* Its ok that this object goes out of scope, as it
106 * wont be stored, and its values will be copied */
107 struct pceplib_infra_config infra
= {
108 /* Memory infrastructure */
109 .pceplib_infra_mt
= MTYPE_PCEPLIB_INFRA
,
110 .pceplib_messages_mt
= MTYPE_PCEPLIB_MESSAGES
,
111 .malloc_func
= (pceplib_malloc_func
)qmalloc
,
112 .calloc_func
= (pceplib_calloc_func
)qcalloc
,
113 .realloc_func
= (pceplib_realloc_func
)qrealloc
,
114 .strdup_func
= (pceplib_strdup_func
)qstrdup
,
115 .free_func
= (pceplib_free_func
)qfree
,
116 /* Timers infrastructure */
117 .external_infra_data
= fpt
,
118 .socket_read_func
= pcep_lib_pceplib_socket_read_cb
,
119 .socket_write_func
= pcep_lib_pceplib_socket_write_cb
,
121 .pcep_event_func
= pcep_lib_pceplib_event_cb
,
122 /* PCEPlib pthread creation callback */
123 .pthread_create_func
= pcep_lib_pthread_create_cb
};
124 if (!initialize_pcc_infra(&infra
)) {
125 flog_err(EC_PATH_PCEP_PCC_INIT
, "failed to initialize pceplib");
132 void pcep_lib_finalize(void)
134 PCEP_DEBUG("Finalizing pceplib");
135 if (!destroy_pcc()) {
136 flog_err(EC_PATH_PCEP_PCC_FINI
, "failed to finalize pceplib");
142 pcep_lib_connect(struct ipaddr
*src_addr
, int src_port
, struct ipaddr
*dst_addr
,
143 int dst_port
, short msd
,
144 const struct pcep_config_group_opts
*pcep_options
)
146 pcep_configuration
*config
;
149 config
= create_default_pcep_configuration();
150 config
->dst_pcep_port
= dst_port
;
151 config
->src_pcep_port
= src_port
;
152 if (IS_IPADDR_V6(src_addr
)) {
153 config
->is_src_ipv6
= true;
154 memcpy(&config
->src_ip
.src_ipv6
, &src_addr
->ipaddr_v6
,
155 sizeof(struct in6_addr
));
157 config
->is_src_ipv6
= false;
158 config
->src_ip
.src_ipv4
= src_addr
->ipaddr_v4
;
161 config
->support_stateful_pce_lsp_update
= true;
162 config
->support_pce_lsp_instantiation
= pcep_options
->pce_initiated
;
163 config
->support_include_db_version
= false;
164 config
->support_lsp_triggered_resync
= false;
165 config
->support_lsp_delta_sync
= false;
166 config
->support_pce_triggered_initial_sync
= false;
167 config
->support_sr_te_pst
= true;
168 config
->pcc_can_resolve_nai_to_sid
= false;
170 config
->max_sid_depth
= msd
;
171 config
->pcep_msg_versioning
->draft_ietf_pce_segment_routing_07
=
172 pcep_options
->draft07
;
173 config
->keep_alive_seconds
= pcep_options
->keep_alive_seconds
;
174 config
->min_keep_alive_seconds
= pcep_options
->min_keep_alive_seconds
;
175 config
->max_keep_alive_seconds
= pcep_options
->max_keep_alive_seconds
;
176 config
->dead_timer_seconds
= pcep_options
->dead_timer_seconds
;
177 config
->min_dead_timer_seconds
= pcep_options
->min_dead_timer_seconds
;
178 config
->max_dead_timer_seconds
= pcep_options
->max_dead_timer_seconds
;
179 config
->request_time_seconds
= pcep_options
->pcep_request_time_seconds
;
180 /* TODO when available in the pceplib, set it here
181 pcep_options->state_timeout_inteval_seconds;*/
183 if (pcep_options
->tcp_md5_auth
[0] != '\0') {
184 config
->is_tcp_auth_md5
= true;
185 strlcpy(config
->tcp_authentication_str
,
186 pcep_options
->tcp_md5_auth
,
187 sizeof(config
->tcp_authentication_str
));
189 config
->is_tcp_auth_md5
= false;
192 if (IS_IPADDR_V6(dst_addr
)) {
193 sess
= connect_pce_ipv6(config
, &dst_addr
->ipaddr_v6
);
195 sess
= connect_pce(config
, &dst_addr
->ipaddr_v4
);
197 destroy_pcep_configuration(config
);
201 void pcep_lib_disconnect(pcep_session
*sess
)
203 assert(sess
!= NULL
);
204 disconnect_pce(sess
);
207 /* Callback passed to pceplib to write to a socket.
208 * When the socket is ready to be written to,
209 * pcep_lib_socket_write_ready() will be called */
211 int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
214 return pcep_thread_socket_write(fpt
, thread
, fd
, payload
,
215 pcep_lib_socket_write_ready
);
218 /* Callback passed to pceplib to read from a socket.
219 * When the socket is ready to be read from,
220 * pcep_lib_socket_read_ready() will be called */
222 int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
225 return pcep_thread_socket_read(fpt
, thread
, fd
, payload
,
226 pcep_lib_socket_read_ready
);
229 /* Callbacks called by path_pcep_controller when a socket is ready to read/write
232 void pcep_lib_socket_write_ready(struct thread
*thread
)
234 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
235 assert(data
!= NULL
);
237 pceplib_external_socket_write(data
->fd
, data
->payload
);
238 XFREE(MTYPE_PCEP
, data
);
241 void pcep_lib_socket_read_ready(struct thread
*thread
)
243 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
244 assert(data
!= NULL
);
246 pceplib_external_socket_read(data
->fd
, data
->payload
);
247 XFREE(MTYPE_PCEP
, data
);
250 /* Callback passed to pceplib when a pcep_event is ready */
251 void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
)
253 pcep_thread_send_ctrl_event(fpt
, event
, pcep_thread_pcep_event
);
256 /* Wrapper function around the actual pceplib thread start function */
257 void *pcep_lib_pthread_start_passthrough(void *data
)
259 struct frr_pthread
*fpt
= data
;
260 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= fpt
->data
;
261 void *start_routine_data
= passthrough_data
->data
;
262 void *(*start_routine
)(void *) = passthrough_data
->start_routine
;
263 XFREE(MTYPE_PCEP
, passthrough_data
);
265 if (start_routine
!= NULL
) {
266 return start_routine(start_routine_data
);
272 int pcep_lib_pthread_create_cb(pthread_t
*thread_id
, const pthread_attr_t
*attr
,
273 void *(*start_routine
)(void *), void *data
,
274 const char *thread_name
)
276 /* Since FRR calls the start_routine with a struct frr_pthread,
277 * we have to store the real data and callback in a passthrough
278 * and pass the actual data the start_routine needs */
279 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= XMALLOC(
280 MTYPE_PCEP
, sizeof(struct pcep_lib_pthread_passthrough_data
));
281 passthrough_data
->data
= data
;
282 passthrough_data
->start_routine
= start_routine
;
284 struct frr_pthread_attr fpt_attr
= {
285 .start
= pcep_lib_pthread_start_passthrough
,
286 .stop
= pcep_lib_pthread_stop_cb
};
287 struct frr_pthread
*fpt
=
288 frr_pthread_new(&fpt_attr
, thread_name
, "pcep_lib");
293 fpt
->data
= passthrough_data
;
294 int retval
= frr_pthread_run(fpt
, attr
);
299 *thread_id
= fpt
->thread
;
304 int pcep_lib_pthread_stop_cb(struct frr_pthread
*fpt
, void **res
)
307 frr_pthread_destroy(fpt
);
312 struct pcep_message
*pcep_lib_format_report(struct pcep_caps
*caps
,
315 double_linked_list
*objs
= pcep_lib_format_path(caps
, path
);
316 return pcep_msg_create_report(objs
);
319 static struct pcep_object_rp
*create_rp(uint32_t reqid
)
321 double_linked_list
*rp_tlvs
;
322 struct pcep_object_tlv_path_setup_type
*setup_type_tlv
;
323 struct pcep_object_rp
*rp
;
325 rp_tlvs
= dll_initialize();
326 setup_type_tlv
= pcep_tlv_create_path_setup_type(SR_TE_PST
);
327 dll_append(rp_tlvs
, setup_type_tlv
);
329 rp
= pcep_obj_create_rp(0, false, false, false, true, reqid
, rp_tlvs
);
334 struct pcep_message
*pcep_lib_format_request(struct pcep_caps
*caps
,
337 struct ipaddr
*src
= &path
->pcc_addr
;
338 struct ipaddr
*dst
= &path
->nbkey
.endpoint
;
339 double_linked_list
*objs
;
340 struct pcep_object_rp
*rp
;
341 struct pcep_object_endpoints_ipv4
*endpoints_ipv4
;
342 struct pcep_object_endpoints_ipv6
*endpoints_ipv6
;
343 struct pcep_object_objective_function
*of
= NULL
;
344 enum objfun_type objfun
= OBJFUN_UNDEFINED
;
346 assert(src
->ipa_type
== dst
->ipa_type
);
348 objs
= dll_initialize();
349 rp
= create_rp(path
->req_id
);
350 rp
->header
.flag_p
= true;
352 pcep_lib_format_constraints(path
, objs
);
354 /* Objective Function */
355 if (path
->has_pcc_objfun
) {
356 objfun
= path
->pcc_objfun
;
359 if (objfun
!= OBJFUN_UNDEFINED
) {
360 of
= pcep_obj_create_objective_function(objfun
, NULL
);
362 of
->header
.flag_p
= path
->enforce_pcc_objfun
;
363 dll_append(objs
, of
);
366 if (IS_IPADDR_V6(src
)) {
367 endpoints_ipv6
= pcep_obj_create_endpoint_ipv6(&src
->ipaddr_v6
,
369 endpoints_ipv6
->header
.flag_p
= true;
370 return pcep_msg_create_request_ipv6(rp
, endpoints_ipv6
, objs
);
372 endpoints_ipv4
= pcep_obj_create_endpoint_ipv4(&src
->ipaddr_v4
,
374 endpoints_ipv4
->header
.flag_p
= true;
375 return pcep_msg_create_request(rp
, endpoints_ipv4
, objs
);
379 struct pcep_message
*pcep_lib_format_error(int error_type
, int error_value
,
382 double_linked_list
*objs
, *srp_tlvs
;
383 struct pcep_object_srp
*srp
;
384 struct pcep_object_tlv_header
*tlv
;
386 if ((path
== NULL
) || (path
->srp_id
== 0))
387 return pcep_msg_create_error(error_type
, error_value
);
389 objs
= dll_initialize();
390 srp_tlvs
= dll_initialize();
391 tlv
= (struct pcep_object_tlv_header
*)pcep_tlv_create_path_setup_type(
393 dll_append(srp_tlvs
, tlv
);
394 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
, srp_tlvs
);
395 dll_append(objs
, srp
);
396 return pcep_msg_create_error_with_objects(error_type
, error_value
,
400 struct pcep_message
*pcep_lib_format_request_cancelled(uint32_t reqid
)
402 struct pcep_object_notify
*notify
;
403 double_linked_list
*objs
;
404 struct pcep_object_rp
*rp
;
406 notify
= pcep_obj_create_notify(
407 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED
,
408 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST
);
409 objs
= dll_initialize();
410 rp
= create_rp(reqid
);
411 dll_append(objs
, rp
);
413 return pcep_msg_create_notify(notify
, objs
);
416 struct path
*pcep_lib_parse_path(struct pcep_message
*msg
)
419 double_linked_list
*objs
= msg
->obj_list
;
420 double_linked_list_node
*node
;
422 struct pcep_object_header
*obj
;
423 struct pcep_object_rp
*rp
= NULL
;
424 struct pcep_object_srp
*srp
= NULL
;
425 struct pcep_object_lsp
*lsp
= NULL
;
426 struct pcep_object_lspa
*lspa
= NULL
;
427 struct pcep_object_ro
*ero
= NULL
;
428 struct pcep_object_metric
*metric
= NULL
;
429 struct pcep_object_bandwidth
*bandwidth
= NULL
;
430 struct pcep_object_objective_function
*of
= NULL
;
431 struct pcep_object_endpoints_ipv4
*epv4
= NULL
;
432 struct pcep_object_endpoints_ipv6
*epv6
= NULL
;
433 struct pcep_object_vendor_info
*vendor_info
= NULL
;
435 path
= pcep_new_path();
437 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
438 obj
= (struct pcep_object_header
*)node
->data
;
439 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
440 case CLASS_TYPE(PCEP_OBJ_CLASS_RP
, PCEP_OBJ_TYPE_RP
):
442 rp
= (struct pcep_object_rp
*)obj
;
443 pcep_lib_parse_rp(path
, rp
);
445 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_TYPE_SRP
):
447 srp
= (struct pcep_object_srp
*)obj
;
448 pcep_lib_parse_srp(path
, srp
);
450 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP
, PCEP_OBJ_TYPE_LSP
):
451 /* Only support single LSP per message */
453 lsp
= (struct pcep_object_lsp
*)obj
;
454 pcep_lib_parse_lsp(path
, lsp
);
456 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA
, PCEP_OBJ_TYPE_LSPA
):
457 assert(lspa
== NULL
);
458 lspa
= (struct pcep_object_lspa
*)obj
;
459 pcep_lib_parse_lspa(path
, lspa
);
461 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO
, PCEP_OBJ_TYPE_ERO
):
462 /* Only support single ERO per message */
464 ero
= (struct pcep_object_ro
*)obj
;
465 pcep_lib_parse_ero(path
, ero
);
467 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC
, PCEP_OBJ_TYPE_METRIC
):
468 metric
= (struct pcep_object_metric
*)obj
;
469 pcep_lib_parse_metric(path
, metric
);
471 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
472 PCEP_OBJ_TYPE_BANDWIDTH_REQ
):
473 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
474 PCEP_OBJ_TYPE_BANDWIDTH_CISCO
):
475 bandwidth
= (struct pcep_object_bandwidth
*)obj
;
476 path
->has_bandwidth
= true;
477 path
->bandwidth
= bandwidth
->bandwidth
;
479 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH
, PCEP_OBJ_TYPE_NOPATH
):
480 path
->no_path
= true;
482 case CLASS_TYPE(PCEP_OBJ_CLASS_OF
, PCEP_OBJ_TYPE_OF
):
483 of
= (struct pcep_object_objective_function
*)obj
;
484 path
->has_pce_objfun
= true;
485 path
->pce_objfun
= of
->of_code
;
487 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
488 PCEP_OBJ_TYPE_ENDPOINT_IPV4
):
489 epv4
= (struct pcep_object_endpoints_ipv4
*)obj
;
490 pcep_lib_parse_endpoints_ipv4(path
, epv4
);
492 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
493 PCEP_OBJ_TYPE_ENDPOINT_IPV6
):
494 epv6
= (struct pcep_object_endpoints_ipv6
*)obj
;
495 pcep_lib_parse_endpoints_ipv6(path
, epv6
);
497 case CLASS_TYPE(PCEP_OBJ_CLASS_VENDOR_INFO
,
498 PCEP_OBJ_TYPE_VENDOR_INFO
):
499 vendor_info
= (struct pcep_object_vendor_info
*)obj
;
500 pcep_lib_parse_vendor_info(path
, vendor_info
);
503 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
504 "Unexpected PCEP object %s (%u) / %s (%u)",
505 pcep_object_class_name(obj
->object_class
),
507 pcep_object_type_name(obj
->object_class
,
517 void pcep_lib_parse_capabilities(struct pcep_message
*msg
,
518 struct pcep_caps
*caps
)
520 double_linked_list
*objs
= msg
->obj_list
;
521 double_linked_list_node
*node
;
523 struct pcep_object_header
*obj
;
524 struct pcep_object_open
*open
= NULL
;
526 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
527 obj
= (struct pcep_object_header
*)node
->data
;
528 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
529 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN
, PCEP_OBJ_TYPE_OPEN
):
530 assert(open
== NULL
);
531 open
= (struct pcep_object_open
*)obj
;
532 pcep_lib_parse_open(caps
, open
);
535 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
536 "Unexpected PCEP object %s (%u) / %s (%u)",
537 pcep_object_class_name(obj
->object_class
),
539 pcep_object_type_name(obj
->object_class
,
547 struct counters_group
*pcep_lib_copy_counters(pcep_session
*sess
)
549 if (!sess
|| !sess
->pcep_session_counters
) {
553 return copy_counter_group(sess
->pcep_session_counters
);
556 void pcep_lib_free_counters(struct counters_group
*counters
)
558 free_counter_group(counters
);
561 pcep_session
*pcep_lib_copy_pcep_session(pcep_session
*sess
)
568 copy
= XCALLOC(MTYPE_PCEP
, sizeof(*copy
));
569 memcpy(copy
, sess
, sizeof(*copy
));
570 /* These fields should not be accessed */
571 copy
->num_unknown_messages_time_queue
= NULL
;
572 copy
->socket_comm_session
= NULL
;
573 copy
->pcep_session_counters
= NULL
;
578 /* ------------ pceplib logging callback ------------ */
580 int pceplib_logging_cb(int priority
, const char *fmt
, va_list args
)
583 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
584 PCEP_DEBUG_PCEPLIB(priority
, "pceplib: %s", buffer
);
588 /* ------------ Internal Functions ------------ */
590 double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
593 struct in_addr addr_null
;
594 double_linked_list
*objs
, *srp_tlvs
, *lsp_tlvs
, *ero_objs
;
595 struct pcep_object_tlv_header
*tlv
;
596 struct pcep_object_ro_subobj
*ero_obj
;
597 struct pcep_object_srp
*srp
;
598 struct pcep_object_lsp
*lsp
;
599 struct pcep_object_ro
*ero
;
600 uint32_t encoded_binding_sid
;
601 char binding_sid_lsp_tlv_data
[6];
603 memset(&addr_null
, 0, sizeof(addr_null
));
605 objs
= dll_initialize();
607 if (path
->plsp_id
!= 0) {
609 srp_tlvs
= dll_initialize();
610 tlv
= (struct pcep_object_tlv_header
*)
611 pcep_tlv_create_path_setup_type(SR_TE_PST
);
613 dll_append(srp_tlvs
, tlv
);
614 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
,
617 srp
->header
.flag_p
= true;
618 dll_append(objs
, srp
);
622 lsp_tlvs
= dll_initialize();
624 if (path
->plsp_id
== 0 || IS_IPADDR_NONE(&path
->nbkey
.endpoint
)
625 || IS_IPADDR_NONE(&path
->pcc_addr
)) {
626 tlv
= (struct pcep_object_tlv_header
*)
627 pcep_tlv_create_ipv4_lsp_identifiers(
628 &addr_null
, &addr_null
, 0, 0, &addr_null
);
630 assert(path
->pcc_addr
.ipa_type
631 == path
->nbkey
.endpoint
.ipa_type
);
632 if (IS_IPADDR_V4(&path
->pcc_addr
)) {
633 tlv
= (struct pcep_object_tlv_header
*)
634 pcep_tlv_create_ipv4_lsp_identifiers(
635 &path
->pcc_addr
.ipaddr_v4
,
636 &path
->nbkey
.endpoint
.ipaddr_v4
, 0, 0,
637 &path
->pcc_addr
.ipaddr_v4
);
639 tlv
= (struct pcep_object_tlv_header
*)
640 pcep_tlv_create_ipv6_lsp_identifiers(
641 &path
->pcc_addr
.ipaddr_v6
,
642 &path
->nbkey
.endpoint
.ipaddr_v6
, 0, 0,
643 &path
->pcc_addr
.ipaddr_v6
);
647 dll_append(lsp_tlvs
, tlv
);
648 if (path
->name
!= NULL
) {
649 tlv
= (struct pcep_object_tlv_header
*)
650 /*FIXME: Remove the typecasty when pceplib is changed
651 to take a const char* */
652 pcep_tlv_create_symbolic_path_name((char *)path
->name
,
655 dll_append(lsp_tlvs
, tlv
);
657 if ((path
->plsp_id
!= 0) && (path
->binding_sid
!= MPLS_LABEL_NONE
)) {
658 memset(binding_sid_lsp_tlv_data
, 0, 2);
659 encoded_binding_sid
= htonl(path
->binding_sid
<< 12);
660 memcpy(binding_sid_lsp_tlv_data
+ 2, &encoded_binding_sid
, 4);
661 tlv
= (struct pcep_object_tlv_header
*)
662 pcep_tlv_create_tlv_arbitrary(
663 binding_sid_lsp_tlv_data
,
664 sizeof(binding_sid_lsp_tlv_data
),
665 PCEP_OBJ_TYPE_CISCO_BSID
);
667 dll_append(lsp_tlvs
, tlv
);
669 lsp
= pcep_obj_create_lsp(
670 path
->plsp_id
, path
->status
, path
->was_created
/* C Flag */,
671 path
->go_active
/* A Flag */, path
->was_removed
/* R Flag */,
672 path
->is_synching
/* S Flag */, path
->is_delegated
/* D Flag */,
675 lsp
->header
.flag_p
= true;
676 dll_append(objs
, lsp
);
678 ero_objs
= dll_initialize();
679 for (struct path_hop
*hop
= path
->first_hop
; hop
!= NULL
;
683 /* Only supporting MPLS hops with both sid and nai */
684 assert(hop
->is_mpls
);
685 assert(hop
->has_sid
);
687 if (hop
->has_attribs
) {
688 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
,
689 hop
->sid
.mpls
.traffic_class
,
690 hop
->sid
.mpls
.is_bottom
,
693 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
, 0, 0, 0);
698 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_ABSENT
);
700 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
);
701 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_UNKNOWN
);
702 switch (hop
->nai
.type
) {
703 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
704 ero_obj
= (struct pcep_object_ro_subobj
*)
705 pcep_obj_create_ro_subobj_sr_ipv4_node(
706 hop
->is_loose
, !hop
->has_sid
,
707 hop
->has_attribs
, /* C Flag */
708 hop
->is_mpls
, /* M Flag */
710 &hop
->nai
.local_addr
.ipaddr_v4
);
712 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
713 ero_obj
= (struct pcep_object_ro_subobj
*)
714 pcep_obj_create_ro_subobj_sr_ipv6_node(
715 hop
->is_loose
, !hop
->has_sid
,
716 hop
->has_attribs
, /* C Flag */
717 hop
->is_mpls
, /* M Flag */
719 &hop
->nai
.local_addr
.ipaddr_v6
);
721 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
722 ero_obj
= (struct pcep_object_ro_subobj
*)
723 pcep_obj_create_ro_subobj_sr_ipv4_adj(
724 hop
->is_loose
, !hop
->has_sid
,
725 hop
->has_attribs
, /* C Flag */
726 hop
->is_mpls
, /* M Flag */
728 &hop
->nai
.local_addr
.ipaddr_v4
,
729 &hop
->nai
.remote_addr
732 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
733 ero_obj
= (struct pcep_object_ro_subobj
*)
734 pcep_obj_create_ro_subobj_sr_ipv6_adj(
735 hop
->is_loose
, !hop
->has_sid
,
736 hop
->has_attribs
, /* C Flag */
737 hop
->is_mpls
, /* M Flag */
739 &hop
->nai
.local_addr
.ipaddr_v6
,
740 &hop
->nai
.remote_addr
743 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
744 ero_obj
= (struct pcep_object_ro_subobj
*)
745 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
746 hop
->is_loose
, !hop
->has_sid
,
747 hop
->has_attribs
, /* C Flag */
748 hop
->is_mpls
, /* M Flag */
750 hop
->nai
.local_addr
.ipaddr_v4
752 hop
->nai
.local_iface
,
753 hop
->nai
.remote_addr
.ipaddr_v4
755 hop
->nai
.remote_iface
);
757 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
758 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
:
759 case PCEP_SR_SUBOBJ_NAI_UNKNOWN
:
763 if (ero_obj
== NULL
) {
764 ero_obj
= (struct pcep_object_ro_subobj
*)
765 pcep_obj_create_ro_subobj_sr_nonai(
767 hop
->has_attribs
, /* C Flag */
768 hop
->is_mpls
); /* M Flag */
770 dll_append(ero_objs
, ero_obj
);
772 ero
= pcep_obj_create_ero(ero_objs
);
774 ero
->header
.flag_p
= true;
775 dll_append(objs
, ero
);
777 if (path
->plsp_id
== 0) {
781 pcep_lib_format_constraints(path
, objs
);
786 void pcep_lib_format_constraints(struct path
*path
, double_linked_list
*objs
)
788 struct pcep_object_metric
*metric
;
789 struct pcep_object_bandwidth
*bandwidth
;
790 struct pcep_object_lspa
*lspa
;
793 if (path
->has_affinity_filters
) {
794 lspa
= pcep_obj_create_lspa(
795 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1],
796 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1],
797 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1],
798 DEFAULT_LSAP_SETUP_PRIO
, DEFAULT_LSAP_HOLDING_PRIO
,
799 DEFAULT_LSAP_LOCAL_PRETECTION
);
800 assert(lspa
!= NULL
);
801 lspa
->header
.flag_p
= true;
802 dll_append(objs
, lspa
);
805 /* Bandwidth Objects */
806 if (path
->has_bandwidth
) {
807 /* Requested Bandwidth */
808 bandwidth
= pcep_obj_create_bandwidth(path
->bandwidth
);
809 assert(bandwidth
!= NULL
);
810 bandwidth
->header
.flag_p
= path
->enforce_bandwidth
;
811 dll_append(objs
, bandwidth
);
815 for (struct path_metric
*m
= path
->first_metric
; m
!= NULL
;
817 metric
= pcep_obj_create_metric(m
->type
, m
->is_bound
,
818 m
->is_computed
, m
->value
);
819 assert(metric
!= NULL
);
820 metric
->header
.flag_p
= m
->enforce
;
821 dll_append(objs
, metric
);
825 void pcep_lib_parse_open(struct pcep_caps
*caps
, struct pcep_object_open
*open
)
827 double_linked_list
*tlvs
= open
->header
.tlv_list
;
828 double_linked_list_node
*node
;
829 struct pcep_object_tlv_header
*tlv_header
;
831 caps
->is_stateful
= false;
832 caps
->supported_ofs_are_known
= false;
833 caps
->supported_ofs
= 0;
835 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
836 tlv_header
= (struct pcep_object_tlv_header
*)node
->data
;
837 switch (tlv_header
->type
) {
838 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
839 pcep_lib_parse_open_pce_capability(caps
, tlv_header
);
841 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
843 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
844 pcep_lib_parse_open_objfun_list(caps
, tlv_header
);
846 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
847 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
848 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
849 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
850 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
851 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
852 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
853 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
854 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
855 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
856 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
857 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
858 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
859 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
860 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
861 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
862 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
863 case PCEP_OBJ_TYPE_CISCO_BSID
:
864 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
865 "Unexpected OPEN's TLV %s (%u)",
866 pcep_tlv_type_name(tlv_header
->type
),
873 void pcep_lib_parse_open_pce_capability(
874 struct pcep_caps
*caps
, struct pcep_object_tlv_header
*tlv_header
)
876 struct pcep_object_tlv_stateful_pce_capability
*tlv
;
877 tlv
= (struct pcep_object_tlv_stateful_pce_capability
*)tlv_header
;
878 caps
->is_stateful
= tlv
->flag_u_lsp_update_capability
;
881 void pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
882 struct pcep_object_tlv_header
*tlv_header
)
884 double_linked_list_node
*node
;
885 struct pcep_object_tlv_of_list
*tlv
;
886 tlv
= (struct pcep_object_tlv_of_list
*)tlv_header
;
888 caps
->supported_ofs_are_known
= true;
889 for (node
= tlv
->of_list
->head
; node
!= NULL
; node
= node
->next_node
) {
890 of_code
= *(uint16_t *)node
->data
;
893 "Ignoring unexpected objective function with code %u",
897 SET_FLAG(caps
->supported_ofs
, of_code
);
901 void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
)
903 double_linked_list
*tlvs
= rp
->header
.tlv_list
;
904 double_linked_list_node
*node
;
905 struct pcep_object_tlv_header
*tlv
;
908 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
909 "Unexpected Empty RP's TLV plsp-id:(%d)",
910 path
? (int32_t)path
->plsp_id
: -1);
913 /* We ignore the other flags and priority for now */
914 path
->req_id
= rp
->request_id
;
915 path
->has_pce_objfun
= false;
916 path
->pce_objfun
= OBJFUN_UNDEFINED
;
918 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
919 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
921 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
922 // TODO: enforce the path setup type is SR_TE_PST
924 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
925 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
926 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
927 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
928 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
929 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
930 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
931 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
932 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
933 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
934 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
935 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
936 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
937 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
938 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
939 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
940 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
941 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
942 case PCEP_OBJ_TYPE_CISCO_BSID
:
943 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
944 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
945 "Unexpected RP's TLV %s (%u)",
946 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
952 void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
)
954 double_linked_list
*tlvs
= srp
->header
.tlv_list
;
955 double_linked_list_node
*node
;
956 struct pcep_object_tlv_header
*tlv
;
958 path
->do_remove
= srp
->flag_lsp_remove
;
959 path
->srp_id
= srp
->srp_id_number
;
962 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
963 "Unexpected Empty SRP's TLV plsp-id:(%d)",
964 path
? (int32_t)path
->plsp_id
: -1);
967 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
968 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
970 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
971 // TODO: enforce the path setup type is SR_TE_PST
973 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
974 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
975 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
976 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
977 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
978 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
979 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
980 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
981 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
982 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
983 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
984 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
985 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
986 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
987 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
988 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
989 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
990 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
991 case PCEP_OBJ_TYPE_CISCO_BSID
:
992 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
993 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
994 "Unexpected SRP's TLV %s (%u)",
995 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
1001 void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
)
1003 double_linked_list
*tlvs
= lsp
->header
.tlv_list
;
1004 double_linked_list_node
*node
;
1005 struct pcep_object_tlv_header
*tlv
;
1006 struct pcep_object_tlv_symbolic_path_name
*name
;
1007 struct pcep_object_tlv_arbitrary
*arb_tlv
;
1009 path
->plsp_id
= lsp
->plsp_id
;
1010 path
->status
= lsp
->operational_status
;
1011 path
->go_active
= lsp
->flag_a
;
1012 path
->was_created
= lsp
->flag_c
;
1013 path
->was_removed
= lsp
->flag_r
;
1014 path
->is_synching
= lsp
->flag_s
;
1015 path
->is_delegated
= lsp
->flag_d
;
1018 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1019 "Unexpected Empty LSP's TLV plsp-id:(%d)",
1020 path
? (int32_t)path
->plsp_id
: -1);
1024 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
1025 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
1026 switch (tlv
->type
) {
1027 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
1028 name
= (struct pcep_object_tlv_symbolic_path_name
*)tlv
;
1029 pcep_lib_parse_lsp_symbolic_name(path
, name
);
1031 case PCEP_OBJ_TYPE_CISCO_BSID
:
1032 arb_tlv
= (struct pcep_object_tlv_arbitrary
*)tlv
;
1033 memcpy(&path
->binding_sid
, arb_tlv
->data
+ 2,
1034 sizeof(path
->binding_sid
));
1035 path
->binding_sid
= ntohl(path
->binding_sid
);
1036 path
->binding_sid
= (path
->binding_sid
>> 12);
1038 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
1039 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
1040 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
1041 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
1042 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
1043 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
1044 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
1045 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
1046 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
1047 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
1048 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
1049 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
1050 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
1051 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
1052 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
1053 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
1054 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
1055 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
1056 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
1057 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1058 "Unexpected LSP TLV %s (%u)",
1059 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
1065 void pcep_lib_parse_lsp_symbolic_name(
1066 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
)
1068 uint16_t size
= tlv
->symbolic_path_name_length
;
1069 assert(path
->name
== NULL
);
1070 size
= size
> MAX_PATH_NAME_SIZE
? MAX_PATH_NAME_SIZE
: size
;
1071 path
->name
= XCALLOC(MTYPE_PCEP
, size
);
1072 strlcpy((char *)path
->name
, tlv
->symbolic_path_name
, size
+ 1);
1075 void pcep_lib_parse_lspa(struct path
*path
, struct pcep_object_lspa
*lspa
)
1077 path
->has_affinity_filters
= true;
1078 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
1079 lspa
->lspa_exclude_any
;
1080 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
1081 lspa
->lspa_include_any
;
1082 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
1083 lspa
->lspa_include_all
;
1086 void pcep_lib_parse_metric(struct path
*path
, struct pcep_object_metric
*obj
)
1088 struct path_metric
*metric
;
1090 metric
= pcep_new_metric();
1091 metric
->type
= obj
->type
;
1092 metric
->is_bound
= obj
->flag_b
;
1093 metric
->is_computed
= obj
->flag_c
;
1094 metric
->value
= obj
->value
;
1095 metric
->next
= path
->first_metric
;
1096 path
->first_metric
= metric
;
1099 void pcep_lib_parse_endpoints_ipv4(struct path
*path
,
1100 struct pcep_object_endpoints_ipv4
*obj
)
1102 SET_IPADDR_V4(&path
->pcc_addr
);
1103 path
->pcc_addr
.ipaddr_v4
= obj
->src_ipv4
;
1104 SET_IPADDR_V4(&path
->nbkey
.endpoint
);
1105 path
->nbkey
.endpoint
.ipaddr_v4
= obj
->dst_ipv4
;
1108 void pcep_lib_parse_endpoints_ipv6(struct path
*path
,
1109 struct pcep_object_endpoints_ipv6
*obj
)
1111 SET_IPADDR_V6(&path
->pcc_addr
);
1112 path
->pcc_addr
.ipaddr_v6
= obj
->src_ipv6
;
1113 SET_IPADDR_V6(&path
->nbkey
.endpoint
);
1114 path
->nbkey
.endpoint
.ipaddr_v6
= obj
->dst_ipv6
;
1117 void pcep_lib_parse_vendor_info(struct path
*path
,
1118 struct pcep_object_vendor_info
*obj
)
1120 if (obj
->enterprise_number
== ENTERPRISE_NUMBER_CISCO
1121 && obj
->enterprise_specific_info
== ENTERPRISE_COLOR_CISCO
)
1122 path
->nbkey
.color
= obj
->enterprise_specific_info1
;
1124 path
->nbkey
.color
= 0;
1127 void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
)
1129 struct path_hop
*hop
= NULL
;
1130 double_linked_list
*objs
= ero
->sub_objects
;
1131 double_linked_list_node
*node
;
1132 struct pcep_object_ro_subobj
*obj
;
1135 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1136 "Unexpected Empty ERO's sub_obj plsp-id:(%d)",
1137 path
? (int32_t)path
->plsp_id
: -1);
1140 for (node
= objs
->tail
; node
!= NULL
; node
= node
->prev_node
) {
1141 obj
= (struct pcep_object_ro_subobj
*)node
->data
;
1142 switch (obj
->ro_subobj_type
) {
1143 case RO_SUBOBJ_TYPE_SR
:
1144 hop
= pcep_lib_parse_ero_sr(
1145 hop
, (struct pcep_ro_subobj_sr
*)obj
);
1147 case RO_SUBOBJ_TYPE_IPV4
:
1148 case RO_SUBOBJ_TYPE_IPV6
:
1149 case RO_SUBOBJ_TYPE_LABEL
:
1150 case RO_SUBOBJ_TYPE_UNNUM
:
1151 case RO_SUBOBJ_TYPE_ASN
:
1152 case RO_SUBOBJ_UNKNOWN
:
1153 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ
,
1154 "Unexpected ERO sub-object %s (%u)",
1155 pcep_ro_type_name(obj
->ro_subobj_type
),
1156 obj
->ro_subobj_type
);
1161 path
->first_hop
= hop
;
1164 struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
1165 struct pcep_ro_subobj_sr
*sr
)
1167 struct path_hop
*hop
= NULL
;
1170 /* Only support IPv4 node with SID */
1171 assert(!sr
->flag_s
);
1174 sid
.mpls
= (struct sid_mpls
){
1175 .label
= GET_SR_ERO_SID_LABEL(sr
->sid
),
1176 .traffic_class
= GET_SR_ERO_SID_TC(sr
->sid
),
1177 .is_bottom
= GET_SR_ERO_SID_S(sr
->sid
),
1178 .ttl
= GET_SR_ERO_SID_TTL(sr
->sid
)};
1180 sid
.value
= sr
->sid
;
1183 hop
= pcep_new_hop();
1184 *hop
= (struct path_hop
){.next
= next
,
1186 sr
->ro_subobj
.flag_subobj_loose_hop
,
1187 .has_sid
= !sr
->flag_s
,
1188 .is_mpls
= sr
->flag_m
,
1189 .has_attribs
= sr
->flag_c
,
1191 .has_nai
= !sr
->flag_f
,
1192 .nai
= {.type
= sr
->nai_type
}};
1195 assert(sr
->nai_list
!= NULL
);
1196 double_linked_list_node
*n
= sr
->nai_list
->head
;
1198 assert(n
->data
!= NULL
);
1199 switch (sr
->nai_type
) {
1200 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
1201 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1202 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1203 sizeof(struct in_addr
));
1205 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
1206 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1207 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1208 sizeof(struct in6_addr
));
1210 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
1211 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1212 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1213 sizeof(struct in_addr
));
1216 assert(n
->data
!= NULL
);
1217 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1218 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1219 sizeof(struct in_addr
));
1221 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
1222 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1223 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1224 sizeof(struct in6_addr
));
1227 assert(n
->data
!= NULL
);
1228 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V6
;
1229 memcpy(&hop
->nai
.remote_addr
.ipaddr_v6
, n
->data
,
1230 sizeof(struct in6_addr
));
1232 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
1233 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1234 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1235 sizeof(struct in_addr
));
1238 assert(n
->data
!= NULL
);
1239 hop
->nai
.local_iface
= *(uint32_t *)n
->data
;
1242 assert(n
->data
!= NULL
);
1243 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1244 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1245 sizeof(struct in_addr
));
1248 assert(n
->data
!= NULL
);
1249 hop
->nai
.remote_iface
= *(uint32_t *)n
->data
;
1251 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
1252 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
:
1253 case PCEP_SR_SUBOBJ_NAI_UNKNOWN
:
1254 hop
->has_nai
= false;
1255 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI
,
1256 "Unexpected SR segment NAI type %s (%u)",
1257 pcep_nai_type_name(sr
->nai_type
),
1266 struct counters_group
*copy_counter_group(struct counters_group
*from
)
1269 struct counters_group
*result
;
1272 assert(from
->max_subgroups
>= from
->num_subgroups
);
1273 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1274 memcpy(result
, from
, sizeof(*result
));
1275 size
= sizeof(struct counters_subgroup
*) * (from
->max_subgroups
+ 1);
1276 result
->subgroups
= XCALLOC(MTYPE_PCEP
, size
);
1277 for (i
= 0; i
<= from
->max_subgroups
; i
++)
1278 result
->subgroups
[i
] =
1279 copy_counter_subgroup(from
->subgroups
[i
]);
1283 struct counters_subgroup
*copy_counter_subgroup(struct counters_subgroup
*from
)
1286 struct counters_subgroup
*result
;
1289 assert(from
->max_counters
>= from
->num_counters
);
1290 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1291 memcpy(result
, from
, sizeof(*result
));
1292 size
= sizeof(struct counter
*) * (from
->max_counters
+ 1);
1293 result
->counters
= XCALLOC(MTYPE_PCEP
, size
);
1294 for (i
= 0; i
<= from
->max_counters
; i
++)
1295 result
->counters
[i
] = copy_counter(from
->counters
[i
]);
1299 struct counter
*copy_counter(struct counter
*from
)
1301 struct counter
*result
;
1304 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1305 memcpy(result
, from
, sizeof(*result
));
1309 void free_counter_group(struct counters_group
*group
)
1314 for (i
= 0; i
<= group
->max_subgroups
; i
++)
1315 free_counter_subgroup(group
->subgroups
[i
]);
1316 XFREE(MTYPE_PCEP
, group
->subgroups
);
1317 XFREE(MTYPE_PCEP
, group
);
1320 void free_counter_subgroup(struct counters_subgroup
*subgroup
)
1323 if (subgroup
== NULL
)
1325 for (i
= 0; i
<= subgroup
->max_counters
; i
++)
1326 free_counter(subgroup
->counters
[i
]);
1327 XFREE(MTYPE_PCEP
, subgroup
->counters
);
1328 XFREE(MTYPE_PCEP
, subgroup
);
1331 void free_counter(struct counter
*counter
)
1333 if (counter
== NULL
)
1335 XFREE(MTYPE_PCEP
, counter
);