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
39 /* pceplib logging callback */
40 static int pceplib_logging_cb(int level
, const char *fmt
, va_list args
);
42 /* Socket callbacks */
43 static int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
45 static int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
47 static int pcep_lib_socket_read_ready(struct thread
*thread
);
48 static int pcep_lib_socket_write_ready(struct thread
*thread
);
50 /* pceplib pcep_event callbacks */
51 static void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
);
53 /* pceplib pthread creation callback */
54 static int pcep_lib_pthread_create_cb(pthread_t
*pthread_id
,
55 const pthread_attr_t
*attr
,
56 void *(*start_routine
)(void *),
57 void *data
, const char *thread_name
);
58 void *pcep_lib_pthread_start_passthrough(void *data
);
59 int pcep_lib_pthread_stop_cb(struct frr_pthread
*, void **);
61 /* Internal functions */
62 static double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
64 static void pcep_lib_format_constraints(struct path
*path
,
65 double_linked_list
*objs
);
66 static void pcep_lib_parse_open(struct pcep_caps
*caps
,
67 struct pcep_object_open
*open
);
69 pcep_lib_parse_open_pce_capability(struct pcep_caps
*caps
,
70 struct pcep_object_tlv_header
*tlv_header
);
72 pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
73 struct pcep_object_tlv_header
*tlv_header
);
74 static void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
);
75 static void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
);
76 static void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
);
77 static void pcep_lib_parse_lspa(struct path
*path
,
78 struct pcep_object_lspa
*lspa
);
79 static void pcep_lib_parse_metric(struct path
*path
,
80 struct pcep_object_metric
*obj
);
81 static void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
);
82 static struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
83 struct pcep_ro_subobj_sr
*sr
);
84 static struct counters_group
*copy_counter_group(struct counters_group
*from
);
85 static struct counters_subgroup
*
86 copy_counter_subgroup(struct counters_subgroup
*from
);
87 static struct counter
*copy_counter(struct counter
*from
);
88 static void free_counter_group(struct counters_group
*group
);
89 static void free_counter_subgroup(struct counters_subgroup
*subgroup
);
90 static void free_counter(struct counter
*counter
);
92 struct pcep_lib_pthread_passthrough_data
{
93 void *(*start_routine
)(void *data
);
97 /* ------------ API Functions ------------ */
99 int pcep_lib_initialize(struct frr_pthread
*fpt
)
101 PCEP_DEBUG("Initializing pceplib");
103 /* Register pceplib logging callback */
104 register_logger(pceplib_logging_cb
);
106 /* Its ok that this object goes out of scope, as it
107 * wont be stored, and its values will be copied */
108 struct pceplib_infra_config infra
= {
109 /* Memory infrastructure */
110 .pceplib_infra_mt
= MTYPE_PCEPLIB_INFRA
,
111 .pceplib_messages_mt
= MTYPE_PCEPLIB_MESSAGES
,
112 .malloc_func
= (pceplib_malloc_func
)qmalloc
,
113 .calloc_func
= (pceplib_calloc_func
)qcalloc
,
114 .realloc_func
= (pceplib_realloc_func
)qrealloc
,
115 .strdup_func
= (pceplib_strdup_func
)qstrdup
,
116 .free_func
= (pceplib_free_func
)qfree
,
117 /* Timers infrastructure */
118 .external_infra_data
= fpt
,
119 .socket_read_func
= pcep_lib_pceplib_socket_read_cb
,
120 .socket_write_func
= pcep_lib_pceplib_socket_write_cb
,
122 .pcep_event_func
= pcep_lib_pceplib_event_cb
,
123 /* PCEPlib pthread creation callback */
124 .pthread_create_func
= pcep_lib_pthread_create_cb
};
125 if (!initialize_pcc_infra(&infra
)) {
126 flog_err(EC_PATH_PCEP_PCC_INIT
, "failed to initialize pceplib");
133 void pcep_lib_finalize(void)
135 PCEP_DEBUG("Finalizing pceplib");
136 if (!destroy_pcc()) {
137 flog_err(EC_PATH_PCEP_PCC_FINI
, "failed to finalize pceplib");
143 pcep_lib_connect(struct ipaddr
*src_addr
, int src_port
, struct ipaddr
*dst_addr
,
144 int dst_port
, short msd
,
145 const struct pcep_config_group_opts
*pcep_options
)
147 pcep_configuration
*config
;
150 config
= create_default_pcep_configuration();
151 config
->dst_pcep_port
= dst_port
;
152 config
->src_pcep_port
= src_port
;
153 if (IS_IPADDR_V6(src_addr
)) {
154 config
->is_src_ipv6
= true;
155 memcpy(&config
->src_ip
.src_ipv6
, &src_addr
->ipaddr_v6
,
156 sizeof(struct in6_addr
));
158 config
->is_src_ipv6
= false;
159 config
->src_ip
.src_ipv4
= src_addr
->ipaddr_v4
;
162 config
->support_stateful_pce_lsp_update
= true;
163 config
->support_pce_lsp_instantiation
= false;
164 config
->support_include_db_version
= false;
165 config
->support_lsp_triggered_resync
= false;
166 config
->support_lsp_delta_sync
= false;
167 config
->support_pce_triggered_initial_sync
= false;
168 config
->support_sr_te_pst
= true;
169 config
->pcc_can_resolve_nai_to_sid
= false;
171 config
->max_sid_depth
= msd
;
172 config
->pcep_msg_versioning
->draft_ietf_pce_segment_routing_07
=
173 pcep_options
->draft07
;
174 config
->keep_alive_seconds
= pcep_options
->keep_alive_seconds
;
175 config
->min_keep_alive_seconds
= pcep_options
->min_keep_alive_seconds
;
176 config
->max_keep_alive_seconds
= pcep_options
->max_keep_alive_seconds
;
177 config
->dead_timer_seconds
= pcep_options
->dead_timer_seconds
;
178 config
->min_dead_timer_seconds
= pcep_options
->min_dead_timer_seconds
;
179 config
->max_dead_timer_seconds
= pcep_options
->max_dead_timer_seconds
;
180 config
->request_time_seconds
= pcep_options
->pcep_request_time_seconds
;
181 /* TODO when available in the pceplib, set it here
182 pcep_options->state_timeout_inteval_seconds;*/
184 if (pcep_options
->tcp_md5_auth
[0] != '\0') {
185 config
->is_tcp_auth_md5
= true;
186 strlcpy(config
->tcp_authentication_str
,
187 pcep_options
->tcp_md5_auth
,
188 sizeof(config
->tcp_authentication_str
));
190 config
->is_tcp_auth_md5
= false;
193 if (IS_IPADDR_V6(dst_addr
)) {
194 sess
= connect_pce_ipv6(config
, &dst_addr
->ipaddr_v6
);
196 sess
= connect_pce(config
, &dst_addr
->ipaddr_v4
);
198 destroy_pcep_configuration(config
);
202 void pcep_lib_disconnect(pcep_session
*sess
)
204 assert(sess
!= NULL
);
205 disconnect_pce(sess
);
208 /* Callback passed to pceplib to write to a socket.
209 * When the socket is ready to be written to,
210 * pcep_lib_socket_write_ready() will be called */
212 int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
215 return pcep_thread_socket_write(fpt
, thread
, fd
, payload
,
216 pcep_lib_socket_write_ready
);
219 /* Callback passed to pceplib to read from a socket.
220 * When the socket is ready to be read from,
221 * pcep_lib_socket_read_ready() will be called */
223 int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
226 return pcep_thread_socket_read(fpt
, thread
, fd
, payload
,
227 pcep_lib_socket_read_ready
);
230 /* Callbacks called by path_pcep_controller when a socket is ready to read/write
233 int pcep_lib_socket_write_ready(struct thread
*thread
)
235 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
236 assert(data
!= NULL
);
238 int retval
= pceplib_external_socket_write(data
->fd
, data
->payload
);
239 XFREE(MTYPE_PCEP
, data
);
244 int pcep_lib_socket_read_ready(struct thread
*thread
)
246 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
247 assert(data
!= NULL
);
249 int retval
= pceplib_external_socket_read(data
->fd
, data
->payload
);
250 XFREE(MTYPE_PCEP
, data
);
255 /* Callback passed to pceplib when a pcep_event is ready */
256 void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
)
258 pcep_thread_send_ctrl_event(fpt
, event
, pcep_thread_pcep_event
);
261 /* Wrapper function around the actual pceplib thread start function */
262 void *pcep_lib_pthread_start_passthrough(void *data
)
264 struct frr_pthread
*fpt
= data
;
265 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= fpt
->data
;
266 void *start_routine_data
= passthrough_data
->data
;
267 void *(*start_routine
)(void *) = passthrough_data
->start_routine
;
268 XFREE(MTYPE_PCEP
, passthrough_data
);
270 if (start_routine
!= NULL
) {
271 return start_routine(start_routine_data
);
277 int pcep_lib_pthread_create_cb(pthread_t
*thread_id
, const pthread_attr_t
*attr
,
278 void *(*start_routine
)(void *), void *data
,
279 const char *thread_name
)
281 /* Since FRR calls the start_routine with a struct frr_pthread,
282 * we have to store the real data and callback in a passthrough
283 * and pass the actual data the start_routine needs */
284 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= XMALLOC(
285 MTYPE_PCEP
, sizeof(struct pcep_lib_pthread_passthrough_data
));
286 passthrough_data
->data
= data
;
287 passthrough_data
->start_routine
= start_routine
;
289 struct frr_pthread_attr fpt_attr
= {
290 .start
= pcep_lib_pthread_start_passthrough
,
291 .stop
= pcep_lib_pthread_stop_cb
};
292 struct frr_pthread
*fpt
=
293 frr_pthread_new(&fpt_attr
, thread_name
, "pcep_lib");
298 fpt
->data
= passthrough_data
;
299 int retval
= frr_pthread_run(fpt
, attr
);
304 *thread_id
= fpt
->thread
;
309 int pcep_lib_pthread_stop_cb(struct frr_pthread
*fpt
, void **res
)
312 frr_pthread_destroy(fpt
);
317 struct pcep_message
*pcep_lib_format_report(struct pcep_caps
*caps
,
320 double_linked_list
*objs
= pcep_lib_format_path(caps
, path
);
321 return pcep_msg_create_report(objs
);
324 static struct pcep_object_rp
*create_rp(uint32_t reqid
)
326 double_linked_list
*rp_tlvs
;
327 struct pcep_object_tlv_path_setup_type
*setup_type_tlv
;
328 struct pcep_object_rp
*rp
;
330 rp_tlvs
= dll_initialize();
331 setup_type_tlv
= pcep_tlv_create_path_setup_type(SR_TE_PST
);
332 dll_append(rp_tlvs
, setup_type_tlv
);
334 rp
= pcep_obj_create_rp(0, false, false, false, true, reqid
, rp_tlvs
);
339 struct pcep_message
*pcep_lib_format_request(struct pcep_caps
*caps
,
342 struct ipaddr
*src
= &path
->pcc_addr
;
343 struct ipaddr
*dst
= &path
->nbkey
.endpoint
;
344 double_linked_list
*objs
;
345 struct pcep_object_rp
*rp
;
346 struct pcep_object_endpoints_ipv4
*endpoints_ipv4
;
347 struct pcep_object_endpoints_ipv6
*endpoints_ipv6
;
348 struct pcep_object_objective_function
*of
= NULL
;
349 enum objfun_type objfun
= OBJFUN_UNDEFINED
;
351 assert(src
->ipa_type
== dst
->ipa_type
);
353 objs
= dll_initialize();
354 rp
= create_rp(path
->req_id
);
355 rp
->header
.flag_p
= true;
357 pcep_lib_format_constraints(path
, objs
);
359 /* Objective Function */
360 if (path
->has_pcc_objfun
) {
361 objfun
= path
->pcc_objfun
;
364 if (objfun
!= OBJFUN_UNDEFINED
) {
365 of
= pcep_obj_create_objective_function(objfun
, NULL
);
367 of
->header
.flag_p
= path
->enforce_pcc_objfun
;
368 dll_append(objs
, of
);
371 if (IS_IPADDR_V6(src
)) {
372 endpoints_ipv6
= pcep_obj_create_endpoint_ipv6(&src
->ipaddr_v6
,
374 endpoints_ipv6
->header
.flag_p
= true;
375 return pcep_msg_create_request_ipv6(rp
, endpoints_ipv6
, objs
);
377 endpoints_ipv4
= pcep_obj_create_endpoint_ipv4(&src
->ipaddr_v4
,
379 endpoints_ipv4
->header
.flag_p
= true;
380 return pcep_msg_create_request(rp
, endpoints_ipv4
, objs
);
384 struct pcep_message
*pcep_lib_format_error(int error_type
, int error_value
)
386 return pcep_msg_create_error(error_type
, error_value
);
389 struct pcep_message
*pcep_lib_format_request_cancelled(uint32_t reqid
)
391 struct pcep_object_notify
*notify
;
392 double_linked_list
*objs
;
393 struct pcep_object_rp
*rp
;
395 notify
= pcep_obj_create_notify(
396 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED
,
397 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST
);
398 objs
= dll_initialize();
399 rp
= create_rp(reqid
);
400 dll_append(objs
, rp
);
402 return pcep_msg_create_notify(notify
, objs
);
405 struct path
*pcep_lib_parse_path(struct pcep_message
*msg
)
408 double_linked_list
*objs
= msg
->obj_list
;
409 double_linked_list_node
*node
;
411 struct pcep_object_header
*obj
;
412 struct pcep_object_rp
*rp
= NULL
;
413 struct pcep_object_srp
*srp
= NULL
;
414 struct pcep_object_lsp
*lsp
= NULL
;
415 struct pcep_object_lspa
*lspa
= NULL
;
416 struct pcep_object_ro
*ero
= NULL
;
417 struct pcep_object_metric
*metric
= NULL
;
418 struct pcep_object_bandwidth
*bandwidth
= NULL
;
419 struct pcep_object_objective_function
*of
= NULL
;
421 path
= pcep_new_path();
423 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
424 obj
= (struct pcep_object_header
*)node
->data
;
425 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
426 case CLASS_TYPE(PCEP_OBJ_CLASS_RP
, PCEP_OBJ_TYPE_RP
):
428 rp
= (struct pcep_object_rp
*)obj
;
429 pcep_lib_parse_rp(path
, rp
);
431 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_TYPE_SRP
):
433 srp
= (struct pcep_object_srp
*)obj
;
434 pcep_lib_parse_srp(path
, srp
);
436 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP
, PCEP_OBJ_TYPE_LSP
):
437 /* Only support single LSP per message */
439 lsp
= (struct pcep_object_lsp
*)obj
;
440 pcep_lib_parse_lsp(path
, lsp
);
442 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA
, PCEP_OBJ_TYPE_LSPA
):
443 assert(lspa
== NULL
);
444 lspa
= (struct pcep_object_lspa
*)obj
;
445 pcep_lib_parse_lspa(path
, lspa
);
447 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO
, PCEP_OBJ_TYPE_ERO
):
448 /* Only support single ERO per message */
450 ero
= (struct pcep_object_ro
*)obj
;
451 pcep_lib_parse_ero(path
, ero
);
453 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC
, PCEP_OBJ_TYPE_METRIC
):
454 metric
= (struct pcep_object_metric
*)obj
;
455 pcep_lib_parse_metric(path
, metric
);
457 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
458 PCEP_OBJ_TYPE_BANDWIDTH_REQ
):
459 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
460 PCEP_OBJ_TYPE_BANDWIDTH_CISCO
):
461 bandwidth
= (struct pcep_object_bandwidth
*)obj
;
462 path
->has_bandwidth
= true;
463 path
->bandwidth
= bandwidth
->bandwidth
;
465 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH
, PCEP_OBJ_TYPE_NOPATH
):
466 path
->no_path
= true;
468 case CLASS_TYPE(PCEP_OBJ_CLASS_OF
, PCEP_OBJ_TYPE_OF
):
469 of
= (struct pcep_object_objective_function
*)obj
;
470 path
->has_pce_objfun
= true;
471 path
->pce_objfun
= of
->of_code
;
474 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
475 "Unexpected PCEP object %s (%u) / %s (%u)",
476 pcep_object_class_name(obj
->object_class
),
478 pcep_object_type_name(obj
->object_class
,
488 void pcep_lib_parse_capabilities(struct pcep_message
*msg
,
489 struct pcep_caps
*caps
)
491 double_linked_list
*objs
= msg
->obj_list
;
492 double_linked_list_node
*node
;
494 struct pcep_object_header
*obj
;
495 struct pcep_object_open
*open
= NULL
;
497 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
498 obj
= (struct pcep_object_header
*)node
->data
;
499 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
500 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN
, PCEP_OBJ_TYPE_OPEN
):
501 assert(open
== NULL
);
502 open
= (struct pcep_object_open
*)obj
;
503 pcep_lib_parse_open(caps
, open
);
506 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
507 "Unexpected PCEP object %s (%u) / %s (%u)",
508 pcep_object_class_name(obj
->object_class
),
510 pcep_object_type_name(obj
->object_class
,
518 struct counters_group
*pcep_lib_copy_counters(pcep_session
*sess
)
520 if (!sess
|| !sess
->pcep_session_counters
) {
524 return copy_counter_group(sess
->pcep_session_counters
);
527 void pcep_lib_free_counters(struct counters_group
*counters
)
529 free_counter_group(counters
);
532 pcep_session
*pcep_lib_copy_pcep_session(pcep_session
*sess
)
539 copy
= XCALLOC(MTYPE_PCEP
, sizeof(*copy
));
540 memcpy(copy
, sess
, sizeof(*copy
));
541 /* These fields should not be accessed */
542 copy
->num_unknown_messages_time_queue
= NULL
;
543 copy
->socket_comm_session
= NULL
;
544 copy
->pcep_session_counters
= NULL
;
549 /* ------------ pceplib logging callback ------------ */
551 int pceplib_logging_cb(int priority
, const char *fmt
, va_list args
)
554 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
555 PCEP_DEBUG_PCEPLIB(priority
, "pceplib: %s", buffer
);
559 /* ------------ Internal Functions ------------ */
561 double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
564 struct in_addr addr_null
;
565 double_linked_list
*objs
, *srp_tlvs
, *lsp_tlvs
, *ero_objs
;
566 struct pcep_object_tlv_header
*tlv
;
567 struct pcep_object_ro_subobj
*ero_obj
;
568 struct pcep_object_srp
*srp
;
569 struct pcep_object_lsp
*lsp
;
570 struct pcep_object_ro
*ero
;
571 uint32_t encoded_binding_sid
;
572 char binding_sid_lsp_tlv_data
[6];
574 memset(&addr_null
, 0, sizeof(addr_null
));
576 objs
= dll_initialize();
578 if (path
->plsp_id
!= 0) {
580 srp_tlvs
= dll_initialize();
581 tlv
= (struct pcep_object_tlv_header
*)
582 pcep_tlv_create_path_setup_type(SR_TE_PST
);
584 dll_append(srp_tlvs
, tlv
);
585 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
,
588 srp
->header
.flag_p
= true;
589 dll_append(objs
, srp
);
593 lsp_tlvs
= dll_initialize();
595 if (path
->plsp_id
== 0 || IS_IPADDR_NONE(&path
->nbkey
.endpoint
)
596 || IS_IPADDR_NONE(&path
->pcc_addr
)) {
597 tlv
= (struct pcep_object_tlv_header
*)
598 pcep_tlv_create_ipv4_lsp_identifiers(
599 &addr_null
, &addr_null
, 0, 0, &addr_null
);
601 assert(path
->pcc_addr
.ipa_type
602 == path
->nbkey
.endpoint
.ipa_type
);
603 if (IS_IPADDR_V4(&path
->pcc_addr
)) {
604 tlv
= (struct pcep_object_tlv_header
*)
605 pcep_tlv_create_ipv4_lsp_identifiers(
606 &path
->pcc_addr
.ipaddr_v4
,
607 &path
->nbkey
.endpoint
.ipaddr_v4
, 0, 0,
608 &path
->pcc_addr
.ipaddr_v4
);
610 tlv
= (struct pcep_object_tlv_header
*)
611 pcep_tlv_create_ipv6_lsp_identifiers(
612 &path
->pcc_addr
.ipaddr_v6
,
613 &path
->nbkey
.endpoint
.ipaddr_v6
, 0, 0,
614 &path
->pcc_addr
.ipaddr_v6
);
618 dll_append(lsp_tlvs
, tlv
);
619 if (path
->name
!= NULL
) {
620 tlv
= (struct pcep_object_tlv_header
*)
621 /*FIXME: Remove the typecasty when pceplib is changed
622 to take a const char* */
623 pcep_tlv_create_symbolic_path_name((char *)path
->name
,
626 dll_append(lsp_tlvs
, tlv
);
628 if ((path
->plsp_id
!= 0) && (path
->binding_sid
!= MPLS_LABEL_NONE
)) {
629 memset(binding_sid_lsp_tlv_data
, 0, 2);
630 encoded_binding_sid
= htonl(path
->binding_sid
<< 12);
631 memcpy(binding_sid_lsp_tlv_data
+ 2, &encoded_binding_sid
, 4);
632 tlv
= (struct pcep_object_tlv_header
*)
633 pcep_tlv_create_tlv_arbitrary(
634 binding_sid_lsp_tlv_data
,
635 sizeof(binding_sid_lsp_tlv_data
), 65505);
637 dll_append(lsp_tlvs
, tlv
);
639 lsp
= pcep_obj_create_lsp(
640 path
->plsp_id
, path
->status
, path
->was_created
/* C Flag */,
641 path
->go_active
/* A Flag */, path
->was_removed
/* R Flag */,
642 path
->is_synching
/* S Flag */, path
->is_delegated
/* D Flag */,
645 lsp
->header
.flag_p
= true;
646 dll_append(objs
, lsp
);
648 ero_objs
= dll_initialize();
649 for (struct path_hop
*hop
= path
->first_hop
; hop
!= NULL
;
653 /* Only supporting MPLS hops with both sid and nai */
654 assert(hop
->is_mpls
);
655 assert(hop
->has_sid
);
657 if (hop
->has_attribs
) {
658 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
,
659 hop
->sid
.mpls
.traffic_class
,
660 hop
->sid
.mpls
.is_bottom
,
663 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
, 0, 0, 0);
668 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_ABSENT
);
670 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
);
671 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_UNKNOWN
);
672 switch (hop
->nai
.type
) {
673 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
674 ero_obj
= (struct pcep_object_ro_subobj
*)
675 pcep_obj_create_ro_subobj_sr_ipv4_node(
676 hop
->is_loose
, !hop
->has_sid
,
677 hop
->has_attribs
, /* C Flag */
678 hop
->is_mpls
, /* M Flag */
680 &hop
->nai
.local_addr
.ipaddr_v4
);
682 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
683 ero_obj
= (struct pcep_object_ro_subobj
*)
684 pcep_obj_create_ro_subobj_sr_ipv6_node(
685 hop
->is_loose
, !hop
->has_sid
,
686 hop
->has_attribs
, /* C Flag */
687 hop
->is_mpls
, /* M Flag */
689 &hop
->nai
.local_addr
.ipaddr_v6
);
691 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
692 ero_obj
= (struct pcep_object_ro_subobj
*)
693 pcep_obj_create_ro_subobj_sr_ipv4_adj(
694 hop
->is_loose
, !hop
->has_sid
,
695 hop
->has_attribs
, /* C Flag */
696 hop
->is_mpls
, /* M Flag */
698 &hop
->nai
.local_addr
.ipaddr_v4
,
699 &hop
->nai
.remote_addr
702 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
703 ero_obj
= (struct pcep_object_ro_subobj
*)
704 pcep_obj_create_ro_subobj_sr_ipv6_adj(
705 hop
->is_loose
, !hop
->has_sid
,
706 hop
->has_attribs
, /* C Flag */
707 hop
->is_mpls
, /* M Flag */
709 &hop
->nai
.local_addr
.ipaddr_v6
,
710 &hop
->nai
.remote_addr
713 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
714 ero_obj
= (struct pcep_object_ro_subobj
*)
715 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
716 hop
->is_loose
, !hop
->has_sid
,
717 hop
->has_attribs
, /* C Flag */
718 hop
->is_mpls
, /* M Flag */
720 hop
->nai
.local_addr
.ipaddr_v4
722 hop
->nai
.local_iface
,
723 hop
->nai
.remote_addr
.ipaddr_v4
725 hop
->nai
.remote_iface
);
731 if (ero_obj
== NULL
) {
732 ero_obj
= (struct pcep_object_ro_subobj
*)
733 pcep_obj_create_ro_subobj_sr_nonai(
735 hop
->has_attribs
, /* C Flag */
736 hop
->is_mpls
); /* M Flag */
738 dll_append(ero_objs
, ero_obj
);
740 ero
= pcep_obj_create_ero(ero_objs
);
742 ero
->header
.flag_p
= true;
743 dll_append(objs
, ero
);
745 if (path
->plsp_id
== 0) {
749 pcep_lib_format_constraints(path
, objs
);
754 void pcep_lib_format_constraints(struct path
*path
, double_linked_list
*objs
)
756 struct pcep_object_metric
*metric
;
757 struct pcep_object_bandwidth
*bandwidth
;
758 struct pcep_object_lspa
*lspa
;
761 if (path
->has_affinity_filters
) {
762 lspa
= pcep_obj_create_lspa(
763 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1],
764 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1],
765 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1],
766 DEFAULT_LSAP_SETUP_PRIO
, DEFAULT_LSAP_HOLDING_PRIO
,
767 DEFAULT_LSAP_LOCAL_PRETECTION
);
768 assert(lspa
!= NULL
);
769 lspa
->header
.flag_p
= true;
770 dll_append(objs
, lspa
);
773 /* Bandwidth Objects */
774 if (path
->has_bandwidth
) {
775 /* Requested Bandwidth */
776 bandwidth
= pcep_obj_create_bandwidth(path
->bandwidth
);
777 assert(bandwidth
!= NULL
);
778 bandwidth
->header
.flag_p
= path
->enforce_bandwidth
;
779 dll_append(objs
, bandwidth
);
783 for (struct path_metric
*m
= path
->first_metric
; m
!= NULL
;
785 metric
= pcep_obj_create_metric(m
->type
, m
->is_bound
,
786 m
->is_computed
, m
->value
);
787 assert(metric
!= NULL
);
788 metric
->header
.flag_p
= m
->enforce
;
789 dll_append(objs
, metric
);
793 void pcep_lib_parse_open(struct pcep_caps
*caps
, struct pcep_object_open
*open
)
795 double_linked_list
*tlvs
= open
->header
.tlv_list
;
796 double_linked_list_node
*node
;
797 struct pcep_object_tlv_header
*tlv_header
;
799 caps
->is_stateful
= false;
800 caps
->supported_ofs_are_known
= false;
801 caps
->supported_ofs
= 0;
803 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
804 tlv_header
= (struct pcep_object_tlv_header
*)node
->data
;
805 switch (tlv_header
->type
) {
806 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
807 pcep_lib_parse_open_pce_capability(caps
, tlv_header
);
809 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
811 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
812 pcep_lib_parse_open_objfun_list(caps
, tlv_header
);
815 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
816 "Unexpected OPEN's TLV %s (%u)",
817 pcep_tlv_type_name(tlv_header
->type
),
824 void pcep_lib_parse_open_pce_capability(
825 struct pcep_caps
*caps
, struct pcep_object_tlv_header
*tlv_header
)
827 struct pcep_object_tlv_stateful_pce_capability
*tlv
;
828 tlv
= (struct pcep_object_tlv_stateful_pce_capability
*)tlv_header
;
829 caps
->is_stateful
= tlv
->flag_u_lsp_update_capability
;
832 void pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
833 struct pcep_object_tlv_header
*tlv_header
)
835 double_linked_list_node
*node
;
836 struct pcep_object_tlv_of_list
*tlv
;
837 tlv
= (struct pcep_object_tlv_of_list
*)tlv_header
;
839 caps
->supported_ofs_are_known
= true;
840 for (node
= tlv
->of_list
->head
; node
!= NULL
; node
= node
->next_node
) {
841 of_code
= *(uint16_t *)node
->data
;
844 "Ignoring unexpected objective function with code %u",
848 SET_FLAG(caps
->supported_ofs
, of_code
);
852 void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
)
854 double_linked_list
*tlvs
= rp
->header
.tlv_list
;
855 double_linked_list_node
*node
;
856 struct pcep_object_tlv_header
*tlv
;
858 /* We ignore the other flags and priority for now */
859 path
->req_id
= rp
->request_id
;
860 path
->has_pce_objfun
= false;
861 path
->pce_objfun
= OBJFUN_UNDEFINED
;
863 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
864 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
866 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
867 // TODO: enforce the path setup type is SR_TE_PST
870 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
871 "Unexpected RP's TLV %s (%u)",
872 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
878 void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
)
880 double_linked_list
*tlvs
= srp
->header
.tlv_list
;
881 double_linked_list_node
*node
;
882 struct pcep_object_tlv_header
*tlv
;
884 path
->do_remove
= srp
->flag_lsp_remove
;
885 path
->srp_id
= srp
->srp_id_number
;
887 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
888 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
890 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
891 // TODO: enforce the path setup type is SR_TE_PST
894 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
895 "Unexpected SRP's TLV %s (%u)",
896 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
902 void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
)
904 double_linked_list
*tlvs
= lsp
->header
.tlv_list
;
905 double_linked_list_node
*node
;
906 struct pcep_object_tlv_header
*tlv
;
908 path
->plsp_id
= lsp
->plsp_id
;
909 path
->status
= lsp
->operational_status
;
910 path
->go_active
= lsp
->flag_a
;
911 path
->was_created
= lsp
->flag_c
;
912 path
->was_removed
= lsp
->flag_r
;
913 path
->is_synching
= lsp
->flag_s
;
914 path
->is_delegated
= lsp
->flag_d
;
919 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
920 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
923 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
924 "Unexpected LSP TLV %s (%u)",
925 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
931 void pcep_lib_parse_lspa(struct path
*path
, struct pcep_object_lspa
*lspa
)
933 path
->has_affinity_filters
= true;
934 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
935 lspa
->lspa_exclude_any
;
936 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
937 lspa
->lspa_include_any
;
938 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
939 lspa
->lspa_include_all
;
942 void pcep_lib_parse_metric(struct path
*path
, struct pcep_object_metric
*obj
)
944 struct path_metric
*metric
;
946 metric
= pcep_new_metric();
947 metric
->type
= obj
->type
;
948 metric
->is_bound
= obj
->flag_b
;
949 metric
->is_computed
= obj
->flag_c
;
950 metric
->value
= obj
->value
;
951 metric
->next
= path
->first_metric
;
952 path
->first_metric
= metric
;
955 void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
)
957 struct path_hop
*hop
= NULL
;
958 double_linked_list
*objs
= ero
->sub_objects
;
959 double_linked_list_node
*node
;
960 struct pcep_object_ro_subobj
*obj
;
962 for (node
= objs
->tail
; node
!= NULL
; node
= node
->prev_node
) {
963 obj
= (struct pcep_object_ro_subobj
*)node
->data
;
964 switch (obj
->ro_subobj_type
) {
965 case RO_SUBOBJ_TYPE_SR
:
966 hop
= pcep_lib_parse_ero_sr(
967 hop
, (struct pcep_ro_subobj_sr
*)obj
);
970 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ
,
971 "Unexpected ERO sub-object %s (%u)",
972 pcep_ro_type_name(obj
->ro_subobj_type
),
973 obj
->ro_subobj_type
);
978 path
->first_hop
= hop
;
981 struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
982 struct pcep_ro_subobj_sr
*sr
)
984 struct path_hop
*hop
= NULL
;
987 /* Only support IPv4 node with SID */
991 sid
.mpls
= (struct sid_mpls
){
992 .label
= GET_SR_ERO_SID_LABEL(sr
->sid
),
993 .traffic_class
= GET_SR_ERO_SID_TC(sr
->sid
),
994 .is_bottom
= GET_SR_ERO_SID_S(sr
->sid
),
995 .ttl
= GET_SR_ERO_SID_TTL(sr
->sid
)};
1000 hop
= pcep_new_hop();
1001 *hop
= (struct path_hop
){.next
= next
,
1003 sr
->ro_subobj
.flag_subobj_loose_hop
,
1004 .has_sid
= !sr
->flag_s
,
1005 .is_mpls
= sr
->flag_m
,
1006 .has_attribs
= sr
->flag_c
,
1008 .has_nai
= !sr
->flag_f
,
1009 .nai
= {.type
= sr
->nai_type
}};
1012 assert(sr
->nai_list
!= NULL
);
1013 double_linked_list_node
*n
= sr
->nai_list
->head
;
1015 assert(n
->data
!= NULL
);
1016 switch (sr
->nai_type
) {
1017 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
1018 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1019 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1020 sizeof(struct in_addr
));
1022 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
1023 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1024 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1025 sizeof(struct in6_addr
));
1027 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
1028 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1029 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1030 sizeof(struct in_addr
));
1033 assert(n
->data
!= NULL
);
1034 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1035 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1036 sizeof(struct in_addr
));
1038 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
1039 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1040 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1041 sizeof(struct in6_addr
));
1044 assert(n
->data
!= NULL
);
1045 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V6
;
1046 memcpy(&hop
->nai
.remote_addr
.ipaddr_v6
, n
->data
,
1047 sizeof(struct in6_addr
));
1049 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
1050 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1051 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1052 sizeof(struct in_addr
));
1055 assert(n
->data
!= NULL
);
1056 hop
->nai
.local_iface
= *(uint32_t *)n
->data
;
1059 assert(n
->data
!= NULL
);
1060 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1061 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1062 sizeof(struct in_addr
));
1065 assert(n
->data
!= NULL
);
1066 hop
->nai
.remote_iface
= *(uint32_t *)n
->data
;
1069 hop
->has_nai
= false;
1070 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI
,
1071 "Unexpected SR segment NAI type %s (%u)",
1072 pcep_nai_type_name(sr
->nai_type
),
1081 struct counters_group
*copy_counter_group(struct counters_group
*from
)
1084 struct counters_group
*result
;
1087 assert(from
->max_subgroups
>= from
->num_subgroups
);
1088 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1089 memcpy(result
, from
, sizeof(*result
));
1090 size
= sizeof(struct counters_subgroup
*) * (from
->max_subgroups
+ 1);
1091 result
->subgroups
= XCALLOC(MTYPE_PCEP
, size
);
1092 for (i
= 0; i
<= from
->max_subgroups
; i
++)
1093 result
->subgroups
[i
] =
1094 copy_counter_subgroup(from
->subgroups
[i
]);
1098 struct counters_subgroup
*copy_counter_subgroup(struct counters_subgroup
*from
)
1101 struct counters_subgroup
*result
;
1104 assert(from
->max_counters
>= from
->num_counters
);
1105 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1106 memcpy(result
, from
, sizeof(*result
));
1107 size
= sizeof(struct counter
*) * (from
->max_counters
+ 1);
1108 result
->counters
= XCALLOC(MTYPE_PCEP
, size
);
1109 for (i
= 0; i
<= from
->max_counters
; i
++)
1110 result
->counters
[i
] = copy_counter(from
->counters
[i
]);
1114 struct counter
*copy_counter(struct counter
*from
)
1116 struct counter
*result
;
1119 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1120 memcpy(result
, from
, sizeof(*result
));
1124 void free_counter_group(struct counters_group
*group
)
1129 for (i
= 0; i
<= group
->max_subgroups
; i
++)
1130 free_counter_subgroup(group
->subgroups
[i
]);
1131 XFREE(MTYPE_PCEP
, group
->subgroups
);
1132 XFREE(MTYPE_PCEP
, group
);
1135 void free_counter_subgroup(struct counters_subgroup
*subgroup
)
1138 if (subgroup
== NULL
)
1140 for (i
= 0; i
<= subgroup
->max_counters
; i
++)
1141 free_counter(subgroup
->counters
[i
]);
1142 XFREE(MTYPE_PCEP
, subgroup
->counters
);
1143 XFREE(MTYPE_PCEP
, subgroup
);
1146 void free_counter(struct counter
*counter
)
1148 if (counter
== NULL
)
1150 XFREE(MTYPE_PCEP
, counter
);