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
24 #include "pceplib/pcep_utils_counters.h"
25 #include "pceplib/pcep_timers.h"
26 #include "pathd/path_errors.h"
27 #include "pathd/path_pcep.h"
28 #include "pathd/path_pcep_lib.h"
29 #include "pathd/path_pcep_debug.h"
31 DEFINE_MTYPE_STATIC(PATHD
, PCEPLIB_INFRA
, "PCEPlib Infrastructure");
32 DEFINE_MTYPE_STATIC(PATHD
, PCEPLIB_MESSAGES
, "PCEPlib PCEP Messages");
34 #define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
35 #define DEFAULT_LSAP_SETUP_PRIO 4
36 #define DEFAULT_LSAP_HOLDING_PRIO 4
37 #define DEFAULT_LSAP_LOCAL_PRETECTION false
38 #define MAX_PATH_NAME_SIZE 255
40 /* pceplib logging callback */
41 static int pceplib_logging_cb(int level
, const char *fmt
, va_list args
)
44 /* Socket callbacks */
45 static int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
47 static int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
49 static void pcep_lib_socket_read_ready(struct thread
*thread
);
50 static void pcep_lib_socket_write_ready(struct thread
*thread
);
52 /* pceplib pcep_event callbacks */
53 static void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
);
55 /* pceplib pthread creation callback */
56 static int pcep_lib_pthread_create_cb(pthread_t
*pthread_id
,
57 const pthread_attr_t
*attr
,
58 void *(*start_routine
)(void *),
59 void *data
, const char *thread_name
);
60 void *pcep_lib_pthread_start_passthrough(void *data
);
61 int pcep_lib_pthread_stop_cb(struct frr_pthread
*, void **);
63 /* Internal functions */
64 static double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
66 static void pcep_lib_format_constraints(struct path
*path
,
67 double_linked_list
*objs
);
68 static void pcep_lib_parse_open(struct pcep_caps
*caps
,
69 struct pcep_object_open
*open
);
71 pcep_lib_parse_open_pce_capability(struct pcep_caps
*caps
,
72 struct pcep_object_tlv_header
*tlv_header
);
74 pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
75 struct pcep_object_tlv_header
*tlv_header
);
76 static void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
);
77 static void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
);
78 static void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
);
79 static void pcep_lib_parse_lspa(struct path
*path
,
80 struct pcep_object_lspa
*lspa
);
81 static void pcep_lib_parse_lsp_symbolic_name(
82 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
);
83 static void pcep_lib_parse_metric(struct path
*path
,
84 struct pcep_object_metric
*obj
);
86 pcep_lib_parse_endpoints_ipv4(struct path
*path
,
87 struct pcep_object_endpoints_ipv4
*obj
);
89 pcep_lib_parse_endpoints_ipv6(struct path
*path
,
90 struct pcep_object_endpoints_ipv6
*obj
);
91 static void pcep_lib_parse_vendor_info(struct path
*path
,
92 struct pcep_object_vendor_info
*obj
);
93 static void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
);
94 static struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
95 struct pcep_ro_subobj_sr
*sr
);
96 static struct counters_group
*copy_counter_group(struct counters_group
*from
);
97 static struct counters_subgroup
*
98 copy_counter_subgroup(struct counters_subgroup
*from
);
99 static struct counter
*copy_counter(struct counter
*from
);
100 static void free_counter_group(struct counters_group
*group
);
101 static void free_counter_subgroup(struct counters_subgroup
*subgroup
);
102 static void free_counter(struct counter
*counter
);
104 struct pcep_lib_pthread_passthrough_data
{
105 void *(*start_routine
)(void *data
);
109 /* ------------ API Functions ------------ */
111 int pcep_lib_initialize(struct frr_pthread
*fpt
)
113 PCEP_DEBUG("Initializing pceplib");
115 /* Register pceplib logging callback */
116 register_logger(pceplib_logging_cb
);
118 /* Its ok that this object goes out of scope, as it
119 * wont be stored, and its values will be copied */
120 struct pceplib_infra_config infra
= {
121 /* Memory infrastructure */
122 .pceplib_infra_mt
= MTYPE_PCEPLIB_INFRA
,
123 .pceplib_messages_mt
= MTYPE_PCEPLIB_MESSAGES
,
124 .malloc_func
= (pceplib_malloc_func
)qmalloc
,
125 .calloc_func
= (pceplib_calloc_func
)qcalloc
,
126 .realloc_func
= (pceplib_realloc_func
)qrealloc
,
127 .strdup_func
= (pceplib_strdup_func
)qstrdup
,
128 .free_func
= (pceplib_free_func
)qfree
,
129 /* Timers infrastructure */
130 .external_infra_data
= fpt
,
131 .socket_read_func
= pcep_lib_pceplib_socket_read_cb
,
132 .socket_write_func
= pcep_lib_pceplib_socket_write_cb
,
134 .pcep_event_func
= pcep_lib_pceplib_event_cb
,
135 /* PCEPlib pthread creation callback */
136 .pthread_create_func
= pcep_lib_pthread_create_cb
};
137 if (!initialize_pcc_infra(&infra
)) {
138 flog_err(EC_PATH_PCEP_PCC_INIT
, "failed to initialize pceplib");
145 void pcep_lib_finalize(void)
147 PCEP_DEBUG("Finalizing pceplib");
148 if (!destroy_pcc()) {
149 flog_err(EC_PATH_PCEP_PCC_FINI
, "failed to finalize pceplib");
155 pcep_lib_connect(struct ipaddr
*src_addr
, int src_port
, struct ipaddr
*dst_addr
,
156 int dst_port
, short msd
,
157 const struct pcep_config_group_opts
*pcep_options
)
159 pcep_configuration
*config
;
162 config
= create_default_pcep_configuration();
163 config
->dst_pcep_port
= dst_port
;
164 config
->src_pcep_port
= src_port
;
165 if (IS_IPADDR_V6(src_addr
)) {
166 config
->is_src_ipv6
= true;
167 memcpy(&config
->src_ip
.src_ipv6
, &src_addr
->ipaddr_v6
,
168 sizeof(struct in6_addr
));
170 config
->is_src_ipv6
= false;
171 config
->src_ip
.src_ipv4
= src_addr
->ipaddr_v4
;
174 config
->support_stateful_pce_lsp_update
= true;
175 config
->support_pce_lsp_instantiation
= pcep_options
->pce_initiated
;
176 config
->support_include_db_version
= false;
177 config
->support_lsp_triggered_resync
= false;
178 config
->support_lsp_delta_sync
= false;
179 config
->support_pce_triggered_initial_sync
= false;
180 config
->support_sr_te_pst
= true;
181 config
->pcc_can_resolve_nai_to_sid
= false;
183 config
->max_sid_depth
= msd
;
184 config
->pcep_msg_versioning
->draft_ietf_pce_segment_routing_07
=
185 pcep_options
->draft07
;
186 config
->keep_alive_seconds
= pcep_options
->keep_alive_seconds
;
187 config
->min_keep_alive_seconds
= pcep_options
->min_keep_alive_seconds
;
188 config
->max_keep_alive_seconds
= pcep_options
->max_keep_alive_seconds
;
189 config
->dead_timer_seconds
= pcep_options
->dead_timer_seconds
;
190 config
->min_dead_timer_seconds
= pcep_options
->min_dead_timer_seconds
;
191 config
->max_dead_timer_seconds
= pcep_options
->max_dead_timer_seconds
;
192 config
->request_time_seconds
= pcep_options
->pcep_request_time_seconds
;
193 /* TODO when available in the pceplib, set it here
194 pcep_options->state_timeout_inteval_seconds;*/
196 if (pcep_options
->tcp_md5_auth
[0] != '\0') {
197 config
->is_tcp_auth_md5
= true;
198 strlcpy(config
->tcp_authentication_str
,
199 pcep_options
->tcp_md5_auth
,
200 sizeof(config
->tcp_authentication_str
));
202 config
->is_tcp_auth_md5
= false;
205 if (IS_IPADDR_V6(dst_addr
)) {
206 sess
= connect_pce_ipv6(config
, &dst_addr
->ipaddr_v6
);
208 sess
= connect_pce(config
, &dst_addr
->ipaddr_v4
);
210 destroy_pcep_configuration(config
);
214 void pcep_lib_disconnect(pcep_session
*sess
)
216 assert(sess
!= NULL
);
217 disconnect_pce(sess
);
220 /* Callback passed to pceplib to write to a socket.
221 * When the socket is ready to be written to,
222 * pcep_lib_socket_write_ready() will be called */
224 int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
227 return pcep_thread_socket_write(fpt
, thread
, fd
, payload
,
228 pcep_lib_socket_write_ready
);
231 /* Callback passed to pceplib to read from a socket.
232 * When the socket is ready to be read from,
233 * pcep_lib_socket_read_ready() will be called */
235 int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
238 return pcep_thread_socket_read(fpt
, thread
, fd
, payload
,
239 pcep_lib_socket_read_ready
);
242 /* Callbacks called by path_pcep_controller when a socket is ready to read/write
245 void pcep_lib_socket_write_ready(struct thread
*thread
)
247 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
248 assert(data
!= NULL
);
250 pceplib_external_socket_write(data
->fd
, data
->payload
);
251 XFREE(MTYPE_PCEP
, data
);
254 void pcep_lib_socket_read_ready(struct thread
*thread
)
256 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
257 assert(data
!= NULL
);
259 pceplib_external_socket_read(data
->fd
, data
->payload
);
260 XFREE(MTYPE_PCEP
, data
);
263 /* Callback passed to pceplib when a pcep_event is ready */
264 void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
)
266 pcep_thread_send_ctrl_event(fpt
, event
, pcep_thread_pcep_event
);
269 /* Wrapper function around the actual pceplib thread start function */
270 void *pcep_lib_pthread_start_passthrough(void *data
)
272 struct frr_pthread
*fpt
= data
;
273 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= fpt
->data
;
274 void *start_routine_data
= passthrough_data
->data
;
275 void *(*start_routine
)(void *) = passthrough_data
->start_routine
;
276 XFREE(MTYPE_PCEP
, passthrough_data
);
278 if (start_routine
!= NULL
) {
279 return start_routine(start_routine_data
);
285 int pcep_lib_pthread_create_cb(pthread_t
*thread_id
, const pthread_attr_t
*attr
,
286 void *(*start_routine
)(void *), void *data
,
287 const char *thread_name
)
289 /* Since FRR calls the start_routine with a struct frr_pthread,
290 * we have to store the real data and callback in a passthrough
291 * and pass the actual data the start_routine needs */
292 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= XMALLOC(
293 MTYPE_PCEP
, sizeof(struct pcep_lib_pthread_passthrough_data
));
294 passthrough_data
->data
= data
;
295 passthrough_data
->start_routine
= start_routine
;
297 struct frr_pthread_attr fpt_attr
= {
298 .start
= pcep_lib_pthread_start_passthrough
,
299 .stop
= pcep_lib_pthread_stop_cb
};
300 struct frr_pthread
*fpt
=
301 frr_pthread_new(&fpt_attr
, thread_name
, "pcep_lib");
306 fpt
->data
= passthrough_data
;
307 int retval
= frr_pthread_run(fpt
, attr
);
312 *thread_id
= fpt
->thread
;
317 int pcep_lib_pthread_stop_cb(struct frr_pthread
*fpt
, void **res
)
320 frr_pthread_destroy(fpt
);
325 struct pcep_message
*pcep_lib_format_report(struct pcep_caps
*caps
,
328 double_linked_list
*objs
= pcep_lib_format_path(caps
, path
);
329 return pcep_msg_create_report(objs
);
332 static struct pcep_object_rp
*create_rp(uint32_t reqid
)
334 double_linked_list
*rp_tlvs
;
335 struct pcep_object_tlv_path_setup_type
*setup_type_tlv
;
336 struct pcep_object_rp
*rp
;
338 rp_tlvs
= dll_initialize();
339 setup_type_tlv
= pcep_tlv_create_path_setup_type(SR_TE_PST
);
340 dll_append(rp_tlvs
, setup_type_tlv
);
342 rp
= pcep_obj_create_rp(0, false, false, false, true, reqid
, rp_tlvs
);
347 struct pcep_message
*pcep_lib_format_request(struct pcep_caps
*caps
,
350 struct ipaddr
*src
= &path
->pcc_addr
;
351 struct ipaddr
*dst
= &path
->nbkey
.endpoint
;
352 double_linked_list
*objs
;
353 struct pcep_object_rp
*rp
;
354 struct pcep_object_endpoints_ipv4
*endpoints_ipv4
;
355 struct pcep_object_endpoints_ipv6
*endpoints_ipv6
;
356 struct pcep_object_objective_function
*of
= NULL
;
357 enum objfun_type objfun
= OBJFUN_UNDEFINED
;
359 assert(src
->ipa_type
== dst
->ipa_type
);
361 objs
= dll_initialize();
362 rp
= create_rp(path
->req_id
);
363 rp
->header
.flag_p
= true;
365 pcep_lib_format_constraints(path
, objs
);
367 /* Objective Function */
368 if (path
->has_pcc_objfun
) {
369 objfun
= path
->pcc_objfun
;
372 if (objfun
!= OBJFUN_UNDEFINED
) {
373 of
= pcep_obj_create_objective_function(objfun
, NULL
);
375 of
->header
.flag_p
= path
->enforce_pcc_objfun
;
376 dll_append(objs
, of
);
379 if (IS_IPADDR_V6(src
)) {
380 endpoints_ipv6
= pcep_obj_create_endpoint_ipv6(&src
->ipaddr_v6
,
382 endpoints_ipv6
->header
.flag_p
= true;
383 return pcep_msg_create_request_ipv6(rp
, endpoints_ipv6
, objs
);
385 endpoints_ipv4
= pcep_obj_create_endpoint_ipv4(&src
->ipaddr_v4
,
387 endpoints_ipv4
->header
.flag_p
= true;
388 return pcep_msg_create_request(rp
, endpoints_ipv4
, objs
);
392 struct pcep_message
*pcep_lib_format_error(int error_type
, int error_value
,
395 double_linked_list
*objs
, *srp_tlvs
;
396 struct pcep_object_srp
*srp
;
397 struct pcep_object_tlv_header
*tlv
;
399 if ((path
== NULL
) || (path
->srp_id
== 0))
400 return pcep_msg_create_error(error_type
, error_value
);
402 objs
= dll_initialize();
403 srp_tlvs
= dll_initialize();
404 tlv
= (struct pcep_object_tlv_header
*)pcep_tlv_create_path_setup_type(
406 dll_append(srp_tlvs
, tlv
);
407 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
, srp_tlvs
);
408 dll_append(objs
, srp
);
409 return pcep_msg_create_error_with_objects(error_type
, error_value
,
413 struct pcep_message
*pcep_lib_format_request_cancelled(uint32_t reqid
)
415 struct pcep_object_notify
*notify
;
416 double_linked_list
*objs
;
417 struct pcep_object_rp
*rp
;
419 notify
= pcep_obj_create_notify(
420 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED
,
421 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST
);
422 objs
= dll_initialize();
423 rp
= create_rp(reqid
);
424 dll_append(objs
, rp
);
426 return pcep_msg_create_notify(notify
, objs
);
429 struct path
*pcep_lib_parse_path(struct pcep_message
*msg
)
432 double_linked_list
*objs
= msg
->obj_list
;
433 double_linked_list_node
*node
;
435 struct pcep_object_header
*obj
;
436 struct pcep_object_rp
*rp
= NULL
;
437 struct pcep_object_srp
*srp
= NULL
;
438 struct pcep_object_lsp
*lsp
= NULL
;
439 struct pcep_object_lspa
*lspa
= NULL
;
440 struct pcep_object_ro
*ero
= NULL
;
441 struct pcep_object_metric
*metric
= NULL
;
442 struct pcep_object_bandwidth
*bandwidth
= NULL
;
443 struct pcep_object_objective_function
*of
= NULL
;
444 struct pcep_object_endpoints_ipv4
*epv4
= NULL
;
445 struct pcep_object_endpoints_ipv6
*epv6
= NULL
;
446 struct pcep_object_vendor_info
*vendor_info
= NULL
;
448 path
= pcep_new_path();
450 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
451 obj
= (struct pcep_object_header
*)node
->data
;
452 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
453 case CLASS_TYPE(PCEP_OBJ_CLASS_RP
, PCEP_OBJ_TYPE_RP
):
455 rp
= (struct pcep_object_rp
*)obj
;
456 pcep_lib_parse_rp(path
, rp
);
458 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_TYPE_SRP
):
460 srp
= (struct pcep_object_srp
*)obj
;
461 pcep_lib_parse_srp(path
, srp
);
463 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP
, PCEP_OBJ_TYPE_LSP
):
464 /* Only support single LSP per message */
466 lsp
= (struct pcep_object_lsp
*)obj
;
467 pcep_lib_parse_lsp(path
, lsp
);
469 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA
, PCEP_OBJ_TYPE_LSPA
):
470 assert(lspa
== NULL
);
471 lspa
= (struct pcep_object_lspa
*)obj
;
472 pcep_lib_parse_lspa(path
, lspa
);
474 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO
, PCEP_OBJ_TYPE_ERO
):
475 /* Only support single ERO per message */
477 ero
= (struct pcep_object_ro
*)obj
;
478 pcep_lib_parse_ero(path
, ero
);
480 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC
, PCEP_OBJ_TYPE_METRIC
):
481 metric
= (struct pcep_object_metric
*)obj
;
482 pcep_lib_parse_metric(path
, metric
);
484 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
485 PCEP_OBJ_TYPE_BANDWIDTH_REQ
):
486 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
487 PCEP_OBJ_TYPE_BANDWIDTH_CISCO
):
488 bandwidth
= (struct pcep_object_bandwidth
*)obj
;
489 path
->has_bandwidth
= true;
490 path
->bandwidth
= bandwidth
->bandwidth
;
492 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH
, PCEP_OBJ_TYPE_NOPATH
):
493 path
->no_path
= true;
495 case CLASS_TYPE(PCEP_OBJ_CLASS_OF
, PCEP_OBJ_TYPE_OF
):
496 of
= (struct pcep_object_objective_function
*)obj
;
497 path
->has_pce_objfun
= true;
498 path
->pce_objfun
= of
->of_code
;
500 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
501 PCEP_OBJ_TYPE_ENDPOINT_IPV4
):
502 epv4
= (struct pcep_object_endpoints_ipv4
*)obj
;
503 pcep_lib_parse_endpoints_ipv4(path
, epv4
);
505 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
506 PCEP_OBJ_TYPE_ENDPOINT_IPV6
):
507 epv6
= (struct pcep_object_endpoints_ipv6
*)obj
;
508 pcep_lib_parse_endpoints_ipv6(path
, epv6
);
510 case CLASS_TYPE(PCEP_OBJ_CLASS_VENDOR_INFO
,
511 PCEP_OBJ_TYPE_VENDOR_INFO
):
512 vendor_info
= (struct pcep_object_vendor_info
*)obj
;
513 pcep_lib_parse_vendor_info(path
, vendor_info
);
516 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
517 "Unexpected PCEP object %s (%u) / %s (%u)",
518 pcep_object_class_name(obj
->object_class
),
520 pcep_object_type_name(obj
->object_class
,
530 void pcep_lib_parse_capabilities(struct pcep_message
*msg
,
531 struct pcep_caps
*caps
)
533 double_linked_list
*objs
= msg
->obj_list
;
534 double_linked_list_node
*node
;
536 struct pcep_object_header
*obj
;
537 struct pcep_object_open
*open
= NULL
;
539 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
540 obj
= (struct pcep_object_header
*)node
->data
;
541 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
542 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN
, PCEP_OBJ_TYPE_OPEN
):
543 assert(open
== NULL
);
544 open
= (struct pcep_object_open
*)obj
;
545 pcep_lib_parse_open(caps
, open
);
548 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
549 "Unexpected PCEP object %s (%u) / %s (%u)",
550 pcep_object_class_name(obj
->object_class
),
552 pcep_object_type_name(obj
->object_class
,
560 struct counters_group
*pcep_lib_copy_counters(pcep_session
*sess
)
562 if (!sess
|| !sess
->pcep_session_counters
) {
566 return copy_counter_group(sess
->pcep_session_counters
);
569 void pcep_lib_free_counters(struct counters_group
*counters
)
571 free_counter_group(counters
);
574 pcep_session
*pcep_lib_copy_pcep_session(pcep_session
*sess
)
581 copy
= XCALLOC(MTYPE_PCEP
, sizeof(*copy
));
582 memcpy(copy
, sess
, sizeof(*copy
));
583 /* These fields should not be accessed */
584 copy
->num_unknown_messages_time_queue
= NULL
;
585 copy
->socket_comm_session
= NULL
;
586 copy
->pcep_session_counters
= NULL
;
591 /* ------------ pceplib logging callback ------------ */
593 int pceplib_logging_cb(int priority
, const char *fmt
, va_list args
)
596 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
597 PCEP_DEBUG_PCEPLIB(priority
, "pceplib: %s", buffer
);
601 /* ------------ Internal Functions ------------ */
603 double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
606 struct in_addr addr_null
;
607 double_linked_list
*objs
, *srp_tlvs
, *lsp_tlvs
, *ero_objs
;
608 struct pcep_object_tlv_header
*tlv
;
609 struct pcep_object_ro_subobj
*ero_obj
;
610 struct pcep_object_srp
*srp
;
611 struct pcep_object_lsp
*lsp
;
612 struct pcep_object_ro
*ero
;
613 uint32_t encoded_binding_sid
;
614 char binding_sid_lsp_tlv_data
[6];
616 memset(&addr_null
, 0, sizeof(addr_null
));
618 objs
= dll_initialize();
620 if (path
->plsp_id
!= 0) {
622 srp_tlvs
= dll_initialize();
623 tlv
= (struct pcep_object_tlv_header
*)
624 pcep_tlv_create_path_setup_type(SR_TE_PST
);
626 dll_append(srp_tlvs
, tlv
);
627 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
,
630 srp
->header
.flag_p
= true;
631 dll_append(objs
, srp
);
635 lsp_tlvs
= dll_initialize();
637 if (path
->plsp_id
== 0 || IS_IPADDR_NONE(&path
->nbkey
.endpoint
)
638 || IS_IPADDR_NONE(&path
->pcc_addr
)) {
639 tlv
= (struct pcep_object_tlv_header
*)
640 pcep_tlv_create_ipv4_lsp_identifiers(
641 &addr_null
, &addr_null
, 0, 0, &addr_null
);
643 assert(path
->pcc_addr
.ipa_type
644 == path
->nbkey
.endpoint
.ipa_type
);
645 if (IS_IPADDR_V4(&path
->pcc_addr
)) {
646 tlv
= (struct pcep_object_tlv_header
*)
647 pcep_tlv_create_ipv4_lsp_identifiers(
648 &path
->pcc_addr
.ipaddr_v4
,
649 &path
->nbkey
.endpoint
.ipaddr_v4
, 0, 0,
650 &path
->pcc_addr
.ipaddr_v4
);
652 tlv
= (struct pcep_object_tlv_header
*)
653 pcep_tlv_create_ipv6_lsp_identifiers(
654 &path
->pcc_addr
.ipaddr_v6
,
655 &path
->nbkey
.endpoint
.ipaddr_v6
, 0, 0,
656 &path
->pcc_addr
.ipaddr_v6
);
660 dll_append(lsp_tlvs
, tlv
);
661 if (path
->name
!= NULL
) {
662 tlv
= (struct pcep_object_tlv_header
*)
663 /*FIXME: Remove the typecasty when pceplib is changed
664 to take a const char* */
665 pcep_tlv_create_symbolic_path_name((char *)path
->name
,
668 dll_append(lsp_tlvs
, tlv
);
670 if ((path
->plsp_id
!= 0) && (path
->binding_sid
!= MPLS_LABEL_NONE
)) {
671 memset(binding_sid_lsp_tlv_data
, 0, 2);
672 encoded_binding_sid
= htonl(path
->binding_sid
<< 12);
673 memcpy(binding_sid_lsp_tlv_data
+ 2, &encoded_binding_sid
, 4);
674 tlv
= (struct pcep_object_tlv_header
*)
675 pcep_tlv_create_tlv_arbitrary(
676 binding_sid_lsp_tlv_data
,
677 sizeof(binding_sid_lsp_tlv_data
),
678 PCEP_OBJ_TYPE_CISCO_BSID
);
680 dll_append(lsp_tlvs
, tlv
);
682 lsp
= pcep_obj_create_lsp(
683 path
->plsp_id
, path
->status
, path
->was_created
/* C Flag */,
684 path
->go_active
/* A Flag */, path
->was_removed
/* R Flag */,
685 path
->is_synching
/* S Flag */, path
->is_delegated
/* D Flag */,
688 lsp
->header
.flag_p
= true;
689 dll_append(objs
, lsp
);
691 ero_objs
= dll_initialize();
692 for (struct path_hop
*hop
= path
->first_hop
; hop
!= NULL
;
696 /* Only supporting MPLS hops with both sid and nai */
697 assert(hop
->is_mpls
);
698 assert(hop
->has_sid
);
700 if (hop
->has_attribs
) {
701 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
,
702 hop
->sid
.mpls
.traffic_class
,
703 hop
->sid
.mpls
.is_bottom
,
706 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
, 0, 0, 0);
711 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_ABSENT
);
713 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
);
714 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_UNKNOWN
);
715 switch (hop
->nai
.type
) {
716 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
717 ero_obj
= (struct pcep_object_ro_subobj
*)
718 pcep_obj_create_ro_subobj_sr_ipv4_node(
719 hop
->is_loose
, !hop
->has_sid
,
720 hop
->has_attribs
, /* C Flag */
721 hop
->is_mpls
, /* M Flag */
723 &hop
->nai
.local_addr
.ipaddr_v4
);
725 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
726 ero_obj
= (struct pcep_object_ro_subobj
*)
727 pcep_obj_create_ro_subobj_sr_ipv6_node(
728 hop
->is_loose
, !hop
->has_sid
,
729 hop
->has_attribs
, /* C Flag */
730 hop
->is_mpls
, /* M Flag */
732 &hop
->nai
.local_addr
.ipaddr_v6
);
734 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
735 ero_obj
= (struct pcep_object_ro_subobj
*)
736 pcep_obj_create_ro_subobj_sr_ipv4_adj(
737 hop
->is_loose
, !hop
->has_sid
,
738 hop
->has_attribs
, /* C Flag */
739 hop
->is_mpls
, /* M Flag */
741 &hop
->nai
.local_addr
.ipaddr_v4
,
742 &hop
->nai
.remote_addr
745 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
746 ero_obj
= (struct pcep_object_ro_subobj
*)
747 pcep_obj_create_ro_subobj_sr_ipv6_adj(
748 hop
->is_loose
, !hop
->has_sid
,
749 hop
->has_attribs
, /* C Flag */
750 hop
->is_mpls
, /* M Flag */
752 &hop
->nai
.local_addr
.ipaddr_v6
,
753 &hop
->nai
.remote_addr
756 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
757 ero_obj
= (struct pcep_object_ro_subobj
*)
758 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
759 hop
->is_loose
, !hop
->has_sid
,
760 hop
->has_attribs
, /* C Flag */
761 hop
->is_mpls
, /* M Flag */
763 hop
->nai
.local_addr
.ipaddr_v4
765 hop
->nai
.local_iface
,
766 hop
->nai
.remote_addr
.ipaddr_v4
768 hop
->nai
.remote_iface
);
770 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
771 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
:
772 case PCEP_SR_SUBOBJ_NAI_UNKNOWN
:
776 if (ero_obj
== NULL
) {
777 ero_obj
= (struct pcep_object_ro_subobj
*)
778 pcep_obj_create_ro_subobj_sr_nonai(
780 hop
->has_attribs
, /* C Flag */
781 hop
->is_mpls
); /* M Flag */
783 dll_append(ero_objs
, ero_obj
);
785 ero
= pcep_obj_create_ero(ero_objs
);
787 ero
->header
.flag_p
= true;
788 dll_append(objs
, ero
);
790 if (path
->plsp_id
== 0) {
794 pcep_lib_format_constraints(path
, objs
);
799 void pcep_lib_format_constraints(struct path
*path
, double_linked_list
*objs
)
801 struct pcep_object_metric
*metric
;
802 struct pcep_object_bandwidth
*bandwidth
;
803 struct pcep_object_lspa
*lspa
;
806 if (path
->has_affinity_filters
) {
807 lspa
= pcep_obj_create_lspa(
808 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1],
809 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1],
810 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1],
811 DEFAULT_LSAP_SETUP_PRIO
, DEFAULT_LSAP_HOLDING_PRIO
,
812 DEFAULT_LSAP_LOCAL_PRETECTION
);
813 assert(lspa
!= NULL
);
814 lspa
->header
.flag_p
= true;
815 dll_append(objs
, lspa
);
818 /* Bandwidth Objects */
819 if (path
->has_bandwidth
) {
820 /* Requested Bandwidth */
821 bandwidth
= pcep_obj_create_bandwidth(path
->bandwidth
);
822 assert(bandwidth
!= NULL
);
823 bandwidth
->header
.flag_p
= path
->enforce_bandwidth
;
824 dll_append(objs
, bandwidth
);
828 for (struct path_metric
*m
= path
->first_metric
; m
!= NULL
;
830 metric
= pcep_obj_create_metric(m
->type
, m
->is_bound
,
831 m
->is_computed
, m
->value
);
832 assert(metric
!= NULL
);
833 metric
->header
.flag_p
= m
->enforce
;
834 dll_append(objs
, metric
);
838 void pcep_lib_parse_open(struct pcep_caps
*caps
, struct pcep_object_open
*open
)
840 double_linked_list
*tlvs
= open
->header
.tlv_list
;
841 double_linked_list_node
*node
;
842 struct pcep_object_tlv_header
*tlv_header
;
844 caps
->is_stateful
= false;
845 caps
->supported_ofs_are_known
= false;
846 caps
->supported_ofs
= 0;
848 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
849 tlv_header
= (struct pcep_object_tlv_header
*)node
->data
;
850 switch (tlv_header
->type
) {
851 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
852 pcep_lib_parse_open_pce_capability(caps
, tlv_header
);
854 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
856 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
857 pcep_lib_parse_open_objfun_list(caps
, tlv_header
);
859 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
860 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
861 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
862 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
863 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
864 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
865 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
866 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
867 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
868 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
869 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
870 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
871 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
872 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
873 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
874 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
875 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
876 case PCEP_OBJ_TYPE_CISCO_BSID
:
877 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
878 "Unexpected OPEN's TLV %s (%u)",
879 pcep_tlv_type_name(tlv_header
->type
),
886 void pcep_lib_parse_open_pce_capability(
887 struct pcep_caps
*caps
, struct pcep_object_tlv_header
*tlv_header
)
889 struct pcep_object_tlv_stateful_pce_capability
*tlv
;
890 tlv
= (struct pcep_object_tlv_stateful_pce_capability
*)tlv_header
;
891 caps
->is_stateful
= tlv
->flag_u_lsp_update_capability
;
894 void pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
895 struct pcep_object_tlv_header
*tlv_header
)
897 double_linked_list_node
*node
;
898 struct pcep_object_tlv_of_list
*tlv
;
899 tlv
= (struct pcep_object_tlv_of_list
*)tlv_header
;
901 caps
->supported_ofs_are_known
= true;
902 for (node
= tlv
->of_list
->head
; node
!= NULL
; node
= node
->next_node
) {
903 of_code
= *(uint16_t *)node
->data
;
906 "Ignoring unexpected objective function with code %u",
910 SET_FLAG(caps
->supported_ofs
, of_code
);
914 void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
)
916 double_linked_list
*tlvs
= rp
->header
.tlv_list
;
917 double_linked_list_node
*node
;
918 struct pcep_object_tlv_header
*tlv
;
921 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
922 "Unexpected Empty RP's TLV plsp-id:(%d)",
923 path
? (int32_t)path
->plsp_id
: -1);
926 /* We ignore the other flags and priority for now */
927 path
->req_id
= rp
->request_id
;
928 path
->has_pce_objfun
= false;
929 path
->pce_objfun
= OBJFUN_UNDEFINED
;
931 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
932 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
934 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
935 // TODO: enforce the path setup type is SR_TE_PST
937 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
938 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
939 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
940 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
941 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
942 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
943 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
944 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
945 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
946 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
947 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
948 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
949 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
950 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
951 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
952 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
953 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
954 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
955 case PCEP_OBJ_TYPE_CISCO_BSID
:
956 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
957 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
958 "Unexpected RP's TLV %s (%u)",
959 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
965 void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
)
967 double_linked_list
*tlvs
= srp
->header
.tlv_list
;
968 double_linked_list_node
*node
;
969 struct pcep_object_tlv_header
*tlv
;
971 path
->do_remove
= srp
->flag_lsp_remove
;
972 path
->srp_id
= srp
->srp_id_number
;
975 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
976 "Unexpected Empty SRP's TLV plsp-id:(%d)",
977 path
? (int32_t)path
->plsp_id
: -1);
980 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
981 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
983 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
984 // TODO: enforce the path setup type is SR_TE_PST
986 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
987 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
988 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
989 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
990 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
991 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
992 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
993 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
994 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
995 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
996 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
997 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
998 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
999 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
1000 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
1001 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
1002 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
1003 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
1004 case PCEP_OBJ_TYPE_CISCO_BSID
:
1005 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
1006 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1007 "Unexpected SRP's TLV %s (%u)",
1008 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
1014 void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
)
1016 double_linked_list
*tlvs
= lsp
->header
.tlv_list
;
1017 double_linked_list_node
*node
;
1018 struct pcep_object_tlv_header
*tlv
;
1019 struct pcep_object_tlv_symbolic_path_name
*name
;
1020 struct pcep_object_tlv_arbitrary
*arb_tlv
;
1022 path
->plsp_id
= lsp
->plsp_id
;
1023 path
->status
= lsp
->operational_status
;
1024 path
->go_active
= lsp
->flag_a
;
1025 path
->was_created
= lsp
->flag_c
;
1026 path
->was_removed
= lsp
->flag_r
;
1027 path
->is_synching
= lsp
->flag_s
;
1028 path
->is_delegated
= lsp
->flag_d
;
1031 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1032 "Unexpected Empty LSP's TLV plsp-id:(%d)",
1033 path
? (int32_t)path
->plsp_id
: -1);
1037 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
1038 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
1039 switch (tlv
->type
) {
1040 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
1041 name
= (struct pcep_object_tlv_symbolic_path_name
*)tlv
;
1042 pcep_lib_parse_lsp_symbolic_name(path
, name
);
1044 case PCEP_OBJ_TYPE_CISCO_BSID
:
1045 arb_tlv
= (struct pcep_object_tlv_arbitrary
*)tlv
;
1046 memcpy(&path
->binding_sid
, arb_tlv
->data
+ 2,
1047 sizeof(path
->binding_sid
));
1048 path
->binding_sid
= ntohl(path
->binding_sid
);
1049 path
->binding_sid
= (path
->binding_sid
>> 12);
1051 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
1052 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
1053 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
1054 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
1055 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
1056 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
1057 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
1058 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
1059 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
1060 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
1061 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
1062 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
1063 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
1064 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
1065 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
1066 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
1067 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
1068 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
1069 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
1070 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1071 "Unexpected LSP TLV %s (%u)",
1072 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
1078 void pcep_lib_parse_lsp_symbolic_name(
1079 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
)
1081 uint16_t size
= tlv
->symbolic_path_name_length
;
1082 assert(path
->name
== NULL
);
1083 size
= size
> MAX_PATH_NAME_SIZE
? MAX_PATH_NAME_SIZE
: size
;
1084 path
->name
= XCALLOC(MTYPE_PCEP
, size
);
1085 strlcpy((char *)path
->name
, tlv
->symbolic_path_name
, size
+ 1);
1088 void pcep_lib_parse_lspa(struct path
*path
, struct pcep_object_lspa
*lspa
)
1090 path
->has_affinity_filters
= true;
1091 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
1092 lspa
->lspa_exclude_any
;
1093 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
1094 lspa
->lspa_include_any
;
1095 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
1096 lspa
->lspa_include_all
;
1099 void pcep_lib_parse_metric(struct path
*path
, struct pcep_object_metric
*obj
)
1101 struct path_metric
*metric
;
1103 metric
= pcep_new_metric();
1104 metric
->type
= obj
->type
;
1105 metric
->is_bound
= obj
->flag_b
;
1106 metric
->is_computed
= obj
->flag_c
;
1107 metric
->value
= obj
->value
;
1108 metric
->next
= path
->first_metric
;
1109 path
->first_metric
= metric
;
1112 void pcep_lib_parse_endpoints_ipv4(struct path
*path
,
1113 struct pcep_object_endpoints_ipv4
*obj
)
1115 SET_IPADDR_V4(&path
->pcc_addr
);
1116 path
->pcc_addr
.ipaddr_v4
= obj
->src_ipv4
;
1117 SET_IPADDR_V4(&path
->nbkey
.endpoint
);
1118 path
->nbkey
.endpoint
.ipaddr_v4
= obj
->dst_ipv4
;
1121 void pcep_lib_parse_endpoints_ipv6(struct path
*path
,
1122 struct pcep_object_endpoints_ipv6
*obj
)
1124 SET_IPADDR_V6(&path
->pcc_addr
);
1125 path
->pcc_addr
.ipaddr_v6
= obj
->src_ipv6
;
1126 SET_IPADDR_V6(&path
->nbkey
.endpoint
);
1127 path
->nbkey
.endpoint
.ipaddr_v6
= obj
->dst_ipv6
;
1130 void pcep_lib_parse_vendor_info(struct path
*path
,
1131 struct pcep_object_vendor_info
*obj
)
1133 if (obj
->enterprise_number
== ENTERPRISE_NUMBER_CISCO
1134 && obj
->enterprise_specific_info
== ENTERPRISE_COLOR_CISCO
)
1135 path
->nbkey
.color
= obj
->enterprise_specific_info1
;
1137 path
->nbkey
.color
= 0;
1140 void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
)
1142 struct path_hop
*hop
= NULL
;
1143 double_linked_list
*objs
= ero
->sub_objects
;
1144 double_linked_list_node
*node
;
1145 struct pcep_object_ro_subobj
*obj
;
1148 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1149 "Unexpected Empty ERO's sub_obj plsp-id:(%d)",
1150 path
? (int32_t)path
->plsp_id
: -1);
1153 for (node
= objs
->tail
; node
!= NULL
; node
= node
->prev_node
) {
1154 obj
= (struct pcep_object_ro_subobj
*)node
->data
;
1155 switch (obj
->ro_subobj_type
) {
1156 case RO_SUBOBJ_TYPE_SR
:
1157 hop
= pcep_lib_parse_ero_sr(
1158 hop
, (struct pcep_ro_subobj_sr
*)obj
);
1160 case RO_SUBOBJ_TYPE_IPV4
:
1161 case RO_SUBOBJ_TYPE_IPV6
:
1162 case RO_SUBOBJ_TYPE_LABEL
:
1163 case RO_SUBOBJ_TYPE_UNNUM
:
1164 case RO_SUBOBJ_TYPE_ASN
:
1165 case RO_SUBOBJ_UNKNOWN
:
1166 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ
,
1167 "Unexpected ERO sub-object %s (%u)",
1168 pcep_ro_type_name(obj
->ro_subobj_type
),
1169 obj
->ro_subobj_type
);
1174 path
->first_hop
= hop
;
1177 struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
1178 struct pcep_ro_subobj_sr
*sr
)
1180 struct path_hop
*hop
= NULL
;
1183 /* Only support IPv4 node with SID */
1184 assert(!sr
->flag_s
);
1187 sid
.mpls
= (struct sid_mpls
){
1188 .label
= GET_SR_ERO_SID_LABEL(sr
->sid
),
1189 .traffic_class
= GET_SR_ERO_SID_TC(sr
->sid
),
1190 .is_bottom
= GET_SR_ERO_SID_S(sr
->sid
),
1191 .ttl
= GET_SR_ERO_SID_TTL(sr
->sid
)};
1193 sid
.value
= sr
->sid
;
1196 hop
= pcep_new_hop();
1197 *hop
= (struct path_hop
){.next
= next
,
1199 sr
->ro_subobj
.flag_subobj_loose_hop
,
1200 .has_sid
= !sr
->flag_s
,
1201 .is_mpls
= sr
->flag_m
,
1202 .has_attribs
= sr
->flag_c
,
1204 .has_nai
= !sr
->flag_f
,
1205 .nai
= {.type
= sr
->nai_type
}};
1208 assert(sr
->nai_list
!= NULL
);
1209 double_linked_list_node
*n
= sr
->nai_list
->head
;
1211 assert(n
->data
!= NULL
);
1212 switch (sr
->nai_type
) {
1213 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
1214 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1215 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1216 sizeof(struct in_addr
));
1218 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
1219 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1220 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1221 sizeof(struct in6_addr
));
1223 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
1224 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1225 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1226 sizeof(struct in_addr
));
1229 assert(n
->data
!= NULL
);
1230 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1231 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1232 sizeof(struct in_addr
));
1234 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
1235 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1236 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1237 sizeof(struct in6_addr
));
1240 assert(n
->data
!= NULL
);
1241 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V6
;
1242 memcpy(&hop
->nai
.remote_addr
.ipaddr_v6
, n
->data
,
1243 sizeof(struct in6_addr
));
1245 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
1246 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1247 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1248 sizeof(struct in_addr
));
1251 assert(n
->data
!= NULL
);
1252 hop
->nai
.local_iface
= *(uint32_t *)n
->data
;
1255 assert(n
->data
!= NULL
);
1256 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1257 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1258 sizeof(struct in_addr
));
1261 assert(n
->data
!= NULL
);
1262 hop
->nai
.remote_iface
= *(uint32_t *)n
->data
;
1264 case PCEP_SR_SUBOBJ_NAI_ABSENT
:
1265 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
:
1266 case PCEP_SR_SUBOBJ_NAI_UNKNOWN
:
1267 hop
->has_nai
= false;
1268 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI
,
1269 "Unexpected SR segment NAI type %s (%u)",
1270 pcep_nai_type_name(sr
->nai_type
),
1279 struct counters_group
*copy_counter_group(struct counters_group
*from
)
1282 struct counters_group
*result
;
1285 assert(from
->max_subgroups
>= from
->num_subgroups
);
1286 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1287 memcpy(result
, from
, sizeof(*result
));
1288 size
= sizeof(struct counters_subgroup
*) * (from
->max_subgroups
+ 1);
1289 result
->subgroups
= XCALLOC(MTYPE_PCEP
, size
);
1290 for (i
= 0; i
<= from
->max_subgroups
; i
++)
1291 result
->subgroups
[i
] =
1292 copy_counter_subgroup(from
->subgroups
[i
]);
1296 struct counters_subgroup
*copy_counter_subgroup(struct counters_subgroup
*from
)
1299 struct counters_subgroup
*result
;
1302 assert(from
->max_counters
>= from
->num_counters
);
1303 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1304 memcpy(result
, from
, sizeof(*result
));
1305 size
= sizeof(struct counter
*) * (from
->max_counters
+ 1);
1306 result
->counters
= XCALLOC(MTYPE_PCEP
, size
);
1307 for (i
= 0; i
<= from
->max_counters
; i
++)
1308 result
->counters
[i
] = copy_counter(from
->counters
[i
]);
1312 struct counter
*copy_counter(struct counter
*from
)
1314 struct counter
*result
;
1317 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1318 memcpy(result
, from
, sizeof(*result
));
1322 void free_counter_group(struct counters_group
*group
)
1327 for (i
= 0; i
<= group
->max_subgroups
; i
++)
1328 free_counter_subgroup(group
->subgroups
[i
]);
1329 XFREE(MTYPE_PCEP
, group
->subgroups
);
1330 XFREE(MTYPE_PCEP
, group
);
1333 void free_counter_subgroup(struct counters_subgroup
*subgroup
)
1336 if (subgroup
== NULL
)
1338 for (i
= 0; i
<= subgroup
->max_counters
; i
++)
1339 free_counter(subgroup
->counters
[i
]);
1340 XFREE(MTYPE_PCEP
, subgroup
->counters
);
1341 XFREE(MTYPE_PCEP
, subgroup
);
1344 void free_counter(struct counter
*counter
)
1346 if (counter
== NULL
)
1348 XFREE(MTYPE_PCEP
, counter
);