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
22 #include "pceplib/pcep_utils_counters.h"
23 #include "pceplib/pcep_timers.h"
24 #include "pathd/path_errors.h"
25 #include "pathd/path_memory.h"
26 #include "pathd/path_pcep.h"
27 #include "pathd/path_pcep_lib.h"
28 #include "pathd/path_pcep_debug.h"
29 #include "pathd/path_pcep_memory.h"
31 #define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
32 #define DEFAULT_LSAP_SETUP_PRIO 4
33 #define DEFAULT_LSAP_HOLDING_PRIO 4
34 #define DEFAULT_LSAP_LOCAL_PRETECTION false
36 /* pceplib logging callback */
37 static int pceplib_logging_cb(int level
, const char *fmt
, va_list args
);
39 /* Socket callbacks */
40 static int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
42 static int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
44 static int pcep_lib_socket_read_ready(struct thread
*thread
);
45 static int pcep_lib_socket_write_ready(struct thread
*thread
);
47 /* pceplib pcep_event callbacks */
48 static void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
);
50 /* pceplib pthread creation callback */
51 static int pcep_lib_pthread_create_cb(pthread_t
*pthread_id
,
52 const pthread_attr_t
*attr
,
53 void *(*start_routine
)(void *),
54 void *data
, const char *thread_name
);
55 void *pcep_lib_pthread_start_passthrough(void *data
);
56 int pcep_lib_pthread_stop_cb(struct frr_pthread
*, void **);
58 /* Internal functions */
59 static double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
61 static void pcep_lib_format_constraints(struct path
*path
,
62 double_linked_list
*objs
);
63 static void pcep_lib_parse_open(struct pcep_caps
*caps
,
64 struct pcep_object_open
*open
);
66 pcep_lib_parse_open_pce_capability(struct pcep_caps
*caps
,
67 struct pcep_object_tlv_header
*tlv_header
);
69 pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
70 struct pcep_object_tlv_header
*tlv_header
);
71 static void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
);
72 static void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
);
73 static void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
);
74 static void pcep_lib_parse_lspa(struct path
*path
,
75 struct pcep_object_lspa
*lspa
);
76 static void pcep_lib_parse_metric(struct path
*path
,
77 struct pcep_object_metric
*obj
);
78 static void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
);
79 static struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
80 struct pcep_ro_subobj_sr
*sr
);
81 static struct counters_group
*copy_counter_group(struct counters_group
*from
);
82 static struct counters_subgroup
*
83 copy_counter_subgroup(struct counters_subgroup
*from
);
84 static struct counter
*copy_counter(struct counter
*from
);
85 static void free_counter_group(struct counters_group
*group
);
86 static void free_counter_subgroup(struct counters_subgroup
*subgroup
);
87 static void free_counter(struct counter
*counter
);
89 struct pcep_lib_pthread_passthrough_data
{
90 void *(*start_routine
)(void *data
);
94 /* ------------ API Functions ------------ */
96 int pcep_lib_initialize(struct frr_pthread
*fpt
)
98 PCEP_DEBUG("Initializing pceplib");
100 /* Register pceplib logging callback */
101 register_logger(pceplib_logging_cb
);
103 /* Its ok that this object goes out of scope, as it
104 * wont be stored, and its values will be copied */
105 struct pceplib_infra_config infra
= {
106 /* Memory infrastructure */
107 .pceplib_infra_mt
= MTYPE_PCEPLIB_INFRA
,
108 .pceplib_messages_mt
= MTYPE_PCEPLIB_MESSAGES
,
109 .malloc_func
= (pceplib_malloc_func
)qmalloc
,
110 .calloc_func
= (pceplib_calloc_func
)qcalloc
,
111 .realloc_func
= (pceplib_realloc_func
)qrealloc
,
112 .strdup_func
= (pceplib_strdup_func
)qstrdup
,
113 .free_func
= (pceplib_free_func
)qfree
,
114 /* Timers infrastructure */
115 .external_infra_data
= fpt
,
116 .socket_read_func
= pcep_lib_pceplib_socket_read_cb
,
117 .socket_write_func
= pcep_lib_pceplib_socket_write_cb
,
119 .pcep_event_func
= pcep_lib_pceplib_event_cb
,
120 /* PCEPlib pthread creation callback */
121 .pthread_create_func
= pcep_lib_pthread_create_cb
};
122 if (!initialize_pcc_infra(&infra
)) {
123 flog_err(EC_PATH_PCEP_PCC_INIT
, "failed to initialize pceplib");
130 void pcep_lib_finalize(void)
132 PCEP_DEBUG("Finalizing pceplib");
133 if (!destroy_pcc()) {
134 flog_err(EC_PATH_PCEP_PCC_FINI
, "failed to finalize pceplib");
140 pcep_lib_connect(struct ipaddr
*src_addr
, int src_port
, struct ipaddr
*dst_addr
,
141 int dst_port
, short msd
,
142 const struct pcep_config_group_opts
*pcep_options
)
144 pcep_configuration
*config
;
147 config
= create_default_pcep_configuration();
148 config
->dst_pcep_port
= dst_port
;
149 config
->src_pcep_port
= src_port
;
150 if (IS_IPADDR_V6(src_addr
)) {
151 config
->is_src_ipv6
= true;
152 memcpy(&config
->src_ip
.src_ipv6
, &src_addr
->ipaddr_v6
,
153 sizeof(struct in6_addr
));
155 config
->is_src_ipv6
= false;
156 config
->src_ip
.src_ipv4
= src_addr
->ipaddr_v4
;
159 config
->support_stateful_pce_lsp_update
= true;
160 config
->support_pce_lsp_instantiation
= false;
161 config
->support_include_db_version
= false;
162 config
->support_lsp_triggered_resync
= false;
163 config
->support_lsp_delta_sync
= false;
164 config
->support_pce_triggered_initial_sync
= false;
165 config
->support_sr_te_pst
= true;
166 config
->pcc_can_resolve_nai_to_sid
= false;
168 config
->max_sid_depth
= msd
;
169 config
->pcep_msg_versioning
->draft_ietf_pce_segment_routing_07
=
170 pcep_options
->draft07
;
171 config
->keep_alive_seconds
= pcep_options
->keep_alive_seconds
;
172 config
->min_keep_alive_seconds
= pcep_options
->min_keep_alive_seconds
;
173 config
->max_keep_alive_seconds
= pcep_options
->max_keep_alive_seconds
;
174 config
->dead_timer_seconds
= pcep_options
->dead_timer_seconds
;
175 config
->min_dead_timer_seconds
= pcep_options
->min_dead_timer_seconds
;
176 config
->max_dead_timer_seconds
= pcep_options
->max_dead_timer_seconds
;
177 config
->request_time_seconds
= pcep_options
->pcep_request_time_seconds
;
178 /* TODO when available in the pceplib, set it here
179 pcep_options->state_timeout_inteval_seconds;*/
181 if (pcep_options
->tcp_md5_auth
[0] != '\0') {
182 config
->is_tcp_auth_md5
= true;
183 strlcpy(config
->tcp_authentication_str
,
184 pcep_options
->tcp_md5_auth
,
185 sizeof(config
->tcp_authentication_str
));
187 config
->is_tcp_auth_md5
= false;
190 if (IS_IPADDR_V6(dst_addr
)) {
191 sess
= connect_pce_ipv6(config
, &dst_addr
->ipaddr_v6
);
193 sess
= connect_pce(config
, &dst_addr
->ipaddr_v4
);
195 destroy_pcep_configuration(config
);
199 void pcep_lib_disconnect(pcep_session
*sess
)
201 assert(sess
!= NULL
);
202 disconnect_pce(sess
);
205 /* Callback passed to pceplib to write to a socket.
206 * When the socket is ready to be written to,
207 * pcep_lib_socket_write_ready() will be called */
209 int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
212 return pcep_thread_socket_write(fpt
, thread
, fd
, payload
,
213 pcep_lib_socket_write_ready
);
216 /* Callback passed to pceplib to read from a socket.
217 * When the socket is ready to be read from,
218 * pcep_lib_socket_read_ready() will be called */
220 int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
223 return pcep_thread_socket_read(fpt
, thread
, fd
, payload
,
224 pcep_lib_socket_read_ready
);
227 /* Callbacks called by path_pcep_controller when a socket is ready to read/write
230 int pcep_lib_socket_write_ready(struct thread
*thread
)
232 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
233 assert(data
!= NULL
);
235 int retval
= pceplib_external_socket_write(data
->fd
, data
->payload
);
236 XFREE(MTYPE_PCEP
, data
);
241 int pcep_lib_socket_read_ready(struct thread
*thread
)
243 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
244 assert(data
!= NULL
);
246 int retval
= pceplib_external_socket_read(data
->fd
, data
->payload
);
247 XFREE(MTYPE_PCEP
, data
);
252 /* Callback passed to pceplib when a pcep_event is ready */
253 void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
)
255 pcep_thread_send_ctrl_event(fpt
, event
, pcep_thread_pcep_event
);
258 /* Wrapper function around the actual pceplib thread start function */
259 void *pcep_lib_pthread_start_passthrough(void *data
)
261 struct frr_pthread
*fpt
= data
;
262 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= fpt
->data
;
263 void *start_routine_data
= passthrough_data
->data
;
264 void *(*start_routine
)(void *) = passthrough_data
->start_routine
;
265 XFREE(MTYPE_PCEP
, passthrough_data
);
267 if (start_routine
!= NULL
) {
268 return start_routine(start_routine_data
);
274 int pcep_lib_pthread_create_cb(pthread_t
*thread_id
, const pthread_attr_t
*attr
,
275 void *(*start_routine
)(void *), void *data
,
276 const char *thread_name
)
278 /* Since FRR calls the start_routine with a struct frr_pthread,
279 * we have to store the real data and callback in a passthrough
280 * and pass the actual data the start_routine needs */
281 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= XMALLOC(
282 MTYPE_PCEP
, sizeof(struct pcep_lib_pthread_passthrough_data
));
283 passthrough_data
->data
= data
;
284 passthrough_data
->start_routine
= start_routine
;
286 struct frr_pthread_attr fpt_attr
= {
287 .start
= pcep_lib_pthread_start_passthrough
,
288 .stop
= pcep_lib_pthread_stop_cb
};
289 struct frr_pthread
*fpt
=
290 frr_pthread_new(&fpt_attr
, thread_name
, "pcep_lib");
295 fpt
->data
= passthrough_data
;
296 int retval
= frr_pthread_run(fpt
, attr
);
301 *thread_id
= fpt
->thread
;
306 int pcep_lib_pthread_stop_cb(struct frr_pthread
*fpt
, void **res
)
309 frr_pthread_destroy(fpt
);
314 struct pcep_message
*pcep_lib_format_report(struct pcep_caps
*caps
,
317 double_linked_list
*objs
= pcep_lib_format_path(caps
, path
);
318 return pcep_msg_create_report(objs
);
321 static struct pcep_object_rp
*create_rp(uint32_t reqid
)
323 double_linked_list
*rp_tlvs
;
324 struct pcep_object_tlv_path_setup_type
*setup_type_tlv
;
325 struct pcep_object_rp
*rp
;
327 rp_tlvs
= dll_initialize();
328 setup_type_tlv
= pcep_tlv_create_path_setup_type(SR_TE_PST
);
329 dll_append(rp_tlvs
, setup_type_tlv
);
331 rp
= pcep_obj_create_rp(0, false, false, false, true, reqid
, rp_tlvs
);
336 struct pcep_message
*pcep_lib_format_request(struct pcep_caps
*caps
,
339 struct ipaddr
*src
= &path
->pcc_addr
;
340 struct ipaddr
*dst
= &path
->nbkey
.endpoint
;
341 double_linked_list
*objs
;
342 struct pcep_object_rp
*rp
;
343 struct pcep_object_endpoints_ipv4
*endpoints_ipv4
;
344 struct pcep_object_endpoints_ipv6
*endpoints_ipv6
;
345 struct pcep_object_objective_function
*of
= NULL
;
346 enum objfun_type objfun
= OBJFUN_UNDEFINED
;
348 assert(src
->ipa_type
== dst
->ipa_type
);
350 objs
= dll_initialize();
351 rp
= create_rp(path
->req_id
);
352 rp
->header
.flag_p
= true;
354 pcep_lib_format_constraints(path
, objs
);
356 /* Objective Function */
357 if (path
->has_pcc_objfun
) {
358 objfun
= path
->pcc_objfun
;
361 if (objfun
!= OBJFUN_UNDEFINED
) {
362 of
= pcep_obj_create_objective_function(objfun
, NULL
);
364 of
->header
.flag_p
= path
->enforce_pcc_objfun
;
365 dll_append(objs
, of
);
368 if (IS_IPADDR_V6(src
)) {
369 endpoints_ipv6
= pcep_obj_create_endpoint_ipv6(&src
->ipaddr_v6
,
371 endpoints_ipv6
->header
.flag_p
= true;
372 return pcep_msg_create_request_ipv6(rp
, endpoints_ipv6
, objs
);
374 endpoints_ipv4
= pcep_obj_create_endpoint_ipv4(&src
->ipaddr_v4
,
376 endpoints_ipv4
->header
.flag_p
= true;
377 return pcep_msg_create_request(rp
, endpoints_ipv4
, objs
);
381 struct pcep_message
*pcep_lib_format_error(int error_type
, int error_value
)
383 return pcep_msg_create_error(error_type
, error_value
);
386 struct pcep_message
*pcep_lib_format_request_cancelled(uint32_t reqid
)
388 struct pcep_object_notify
*notify
;
389 double_linked_list
*objs
;
390 struct pcep_object_rp
*rp
;
392 notify
= pcep_obj_create_notify(
393 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED
,
394 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST
);
395 objs
= dll_initialize();
396 rp
= create_rp(reqid
);
397 dll_append(objs
, rp
);
399 return pcep_msg_create_notify(notify
, objs
);
402 struct path
*pcep_lib_parse_path(struct pcep_message
*msg
)
405 double_linked_list
*objs
= msg
->obj_list
;
406 double_linked_list_node
*node
;
408 struct pcep_object_header
*obj
;
409 struct pcep_object_rp
*rp
= NULL
;
410 struct pcep_object_srp
*srp
= NULL
;
411 struct pcep_object_lsp
*lsp
= NULL
;
412 struct pcep_object_lspa
*lspa
= NULL
;
413 struct pcep_object_ro
*ero
= NULL
;
414 struct pcep_object_metric
*metric
= NULL
;
415 struct pcep_object_bandwidth
*bandwidth
= NULL
;
416 struct pcep_object_objective_function
*of
= NULL
;
418 path
= pcep_new_path();
420 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
421 obj
= (struct pcep_object_header
*)node
->data
;
422 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
423 case CLASS_TYPE(PCEP_OBJ_CLASS_RP
, PCEP_OBJ_TYPE_RP
):
425 rp
= (struct pcep_object_rp
*)obj
;
426 pcep_lib_parse_rp(path
, rp
);
428 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_TYPE_SRP
):
430 srp
= (struct pcep_object_srp
*)obj
;
431 pcep_lib_parse_srp(path
, srp
);
433 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP
, PCEP_OBJ_TYPE_LSP
):
434 /* Only support single LSP per message */
436 lsp
= (struct pcep_object_lsp
*)obj
;
437 pcep_lib_parse_lsp(path
, lsp
);
439 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA
, PCEP_OBJ_TYPE_LSPA
):
440 assert(lspa
== NULL
);
441 lspa
= (struct pcep_object_lspa
*)obj
;
442 pcep_lib_parse_lspa(path
, lspa
);
444 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO
, PCEP_OBJ_TYPE_ERO
):
445 /* Only support single ERO per message */
447 ero
= (struct pcep_object_ro
*)obj
;
448 pcep_lib_parse_ero(path
, ero
);
450 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC
, PCEP_OBJ_TYPE_METRIC
):
451 metric
= (struct pcep_object_metric
*)obj
;
452 pcep_lib_parse_metric(path
, metric
);
454 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
455 PCEP_OBJ_TYPE_BANDWIDTH_REQ
):
456 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
457 PCEP_OBJ_TYPE_BANDWIDTH_CISCO
):
458 bandwidth
= (struct pcep_object_bandwidth
*)obj
;
459 path
->has_bandwidth
= true;
460 path
->bandwidth
= bandwidth
->bandwidth
;
462 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH
, PCEP_OBJ_TYPE_NOPATH
):
463 path
->no_path
= true;
465 case CLASS_TYPE(PCEP_OBJ_CLASS_OF
, PCEP_OBJ_TYPE_OF
):
466 of
= (struct pcep_object_objective_function
*)obj
;
467 path
->has_pce_objfun
= true;
468 path
->pce_objfun
= of
->of_code
;
471 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
472 "Unexpected PCEP object %s (%u) / %s (%u)",
473 pcep_object_class_name(obj
->object_class
),
475 pcep_object_type_name(obj
->object_class
,
485 void pcep_lib_parse_capabilities(struct pcep_message
*msg
,
486 struct pcep_caps
*caps
)
488 double_linked_list
*objs
= msg
->obj_list
;
489 double_linked_list_node
*node
;
491 struct pcep_object_header
*obj
;
492 struct pcep_object_open
*open
= NULL
;
494 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
495 obj
= (struct pcep_object_header
*)node
->data
;
496 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
497 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN
, PCEP_OBJ_TYPE_OPEN
):
498 assert(open
== NULL
);
499 open
= (struct pcep_object_open
*)obj
;
500 pcep_lib_parse_open(caps
, open
);
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
,
515 struct counters_group
*pcep_lib_copy_counters(pcep_session
*sess
)
517 if (!sess
|| !sess
->pcep_session_counters
) {
521 return copy_counter_group(sess
->pcep_session_counters
);
524 void pcep_lib_free_counters(struct counters_group
*counters
)
526 free_counter_group(counters
);
529 pcep_session
*pcep_lib_copy_pcep_session(pcep_session
*sess
)
536 copy
= XCALLOC(MTYPE_PCEP
, sizeof(*copy
));
537 memcpy(copy
, sess
, sizeof(*copy
));
538 /* These fields should not be accessed */
539 copy
->num_unknown_messages_time_queue
= NULL
;
540 copy
->socket_comm_session
= NULL
;
541 copy
->pcep_session_counters
= NULL
;
546 /* ------------ pceplib logging callback ------------ */
548 int pceplib_logging_cb(int priority
, const char *fmt
, va_list args
)
551 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
552 PCEP_DEBUG_PCEPLIB(priority
, "pceplib: %s", buffer
);
556 /* ------------ Internal Functions ------------ */
558 double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
561 struct in_addr addr_null
;
562 double_linked_list
*objs
, *srp_tlvs
, *lsp_tlvs
, *ero_objs
;
563 struct pcep_object_tlv_header
*tlv
;
564 struct pcep_object_ro_subobj
*ero_obj
;
565 struct pcep_object_srp
*srp
;
566 struct pcep_object_lsp
*lsp
;
567 struct pcep_object_ro
*ero
;
568 uint32_t encoded_binding_sid
;
569 char binding_sid_lsp_tlv_data
[6];
571 memset(&addr_null
, 0, sizeof(addr_null
));
573 objs
= dll_initialize();
575 if (path
->plsp_id
!= 0) {
577 srp_tlvs
= dll_initialize();
578 tlv
= (struct pcep_object_tlv_header
*)
579 pcep_tlv_create_path_setup_type(SR_TE_PST
);
581 dll_append(srp_tlvs
, tlv
);
582 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
,
585 srp
->header
.flag_p
= true;
586 dll_append(objs
, srp
);
590 lsp_tlvs
= dll_initialize();
592 if (path
->plsp_id
== 0 || IS_IPADDR_NONE(&path
->nbkey
.endpoint
)
593 || IS_IPADDR_NONE(&path
->pcc_addr
)) {
594 tlv
= (struct pcep_object_tlv_header
*)
595 pcep_tlv_create_ipv4_lsp_identifiers(
596 &addr_null
, &addr_null
, 0, 0, &addr_null
);
598 assert(path
->pcc_addr
.ipa_type
599 == path
->nbkey
.endpoint
.ipa_type
);
600 if (IS_IPADDR_V4(&path
->pcc_addr
)) {
601 tlv
= (struct pcep_object_tlv_header
*)
602 pcep_tlv_create_ipv4_lsp_identifiers(
603 &path
->pcc_addr
.ipaddr_v4
,
604 &path
->nbkey
.endpoint
.ipaddr_v4
, 0, 0,
605 &path
->pcc_addr
.ipaddr_v4
);
607 tlv
= (struct pcep_object_tlv_header
*)
608 pcep_tlv_create_ipv6_lsp_identifiers(
609 &path
->pcc_addr
.ipaddr_v6
,
610 &path
->nbkey
.endpoint
.ipaddr_v6
, 0, 0,
611 &path
->pcc_addr
.ipaddr_v6
);
615 dll_append(lsp_tlvs
, tlv
);
616 if (path
->name
!= NULL
) {
617 tlv
= (struct pcep_object_tlv_header
*)
618 /*FIXME: Remove the typecasty when pceplib is changed
619 to take a const char* */
620 pcep_tlv_create_symbolic_path_name((char *)path
->name
,
623 dll_append(lsp_tlvs
, tlv
);
625 if ((path
->plsp_id
!= 0) && (path
->binding_sid
!= MPLS_LABEL_NONE
)) {
626 memset(binding_sid_lsp_tlv_data
, 0, 2);
627 encoded_binding_sid
= htonl(path
->binding_sid
<< 12);
628 memcpy(binding_sid_lsp_tlv_data
+ 2, &encoded_binding_sid
, 4);
629 tlv
= (struct pcep_object_tlv_header
*)
630 pcep_tlv_create_tlv_arbitrary(
631 binding_sid_lsp_tlv_data
,
632 sizeof(binding_sid_lsp_tlv_data
), 65505);
634 dll_append(lsp_tlvs
, tlv
);
636 lsp
= pcep_obj_create_lsp(
637 path
->plsp_id
, path
->status
, path
->was_created
/* C Flag */,
638 path
->go_active
/* A Flag */, path
->was_removed
/* R Flag */,
639 path
->is_synching
/* S Flag */, path
->is_delegated
/* D Flag */,
642 lsp
->header
.flag_p
= true;
643 dll_append(objs
, lsp
);
645 ero_objs
= dll_initialize();
646 for (struct path_hop
*hop
= path
->first_hop
; hop
!= NULL
;
650 /* Only supporting MPLS hops with both sid and nai */
651 assert(hop
->is_mpls
);
652 assert(hop
->has_sid
);
654 if (hop
->has_attribs
) {
655 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
,
656 hop
->sid
.mpls
.traffic_class
,
657 hop
->sid
.mpls
.is_bottom
,
660 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
, 0, 0, 0);
665 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_ABSENT
);
667 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
);
668 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_UNKNOWN
);
669 switch (hop
->nai
.type
) {
670 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
671 ero_obj
= (struct pcep_object_ro_subobj
*)
672 pcep_obj_create_ro_subobj_sr_ipv4_node(
673 hop
->is_loose
, !hop
->has_sid
,
674 hop
->has_attribs
, /* C Flag */
675 hop
->is_mpls
, /* M Flag */
677 &hop
->nai
.local_addr
.ipaddr_v4
);
679 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
680 ero_obj
= (struct pcep_object_ro_subobj
*)
681 pcep_obj_create_ro_subobj_sr_ipv6_node(
682 hop
->is_loose
, !hop
->has_sid
,
683 hop
->has_attribs
, /* C Flag */
684 hop
->is_mpls
, /* M Flag */
686 &hop
->nai
.local_addr
.ipaddr_v6
);
688 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
689 ero_obj
= (struct pcep_object_ro_subobj
*)
690 pcep_obj_create_ro_subobj_sr_ipv4_adj(
691 hop
->is_loose
, !hop
->has_sid
,
692 hop
->has_attribs
, /* C Flag */
693 hop
->is_mpls
, /* M Flag */
695 &hop
->nai
.local_addr
.ipaddr_v4
,
696 &hop
->nai
.remote_addr
699 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
700 ero_obj
= (struct pcep_object_ro_subobj
*)
701 pcep_obj_create_ro_subobj_sr_ipv6_adj(
702 hop
->is_loose
, !hop
->has_sid
,
703 hop
->has_attribs
, /* C Flag */
704 hop
->is_mpls
, /* M Flag */
706 &hop
->nai
.local_addr
.ipaddr_v6
,
707 &hop
->nai
.remote_addr
710 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
711 ero_obj
= (struct pcep_object_ro_subobj
*)
712 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
713 hop
->is_loose
, !hop
->has_sid
,
714 hop
->has_attribs
, /* C Flag */
715 hop
->is_mpls
, /* M Flag */
717 hop
->nai
.local_addr
.ipaddr_v4
719 hop
->nai
.local_iface
,
720 hop
->nai
.remote_addr
.ipaddr_v4
722 hop
->nai
.remote_iface
);
728 if (ero_obj
== NULL
) {
729 ero_obj
= (struct pcep_object_ro_subobj
*)
730 pcep_obj_create_ro_subobj_sr_nonai(
732 hop
->has_attribs
, /* C Flag */
733 hop
->is_mpls
); /* M Flag */
735 dll_append(ero_objs
, ero_obj
);
737 ero
= pcep_obj_create_ero(ero_objs
);
739 ero
->header
.flag_p
= true;
740 dll_append(objs
, ero
);
742 if (path
->plsp_id
== 0) {
746 pcep_lib_format_constraints(path
, objs
);
751 void pcep_lib_format_constraints(struct path
*path
, double_linked_list
*objs
)
753 struct pcep_object_metric
*metric
;
754 struct pcep_object_bandwidth
*bandwidth
;
755 struct pcep_object_lspa
*lspa
;
758 if (path
->has_affinity_filters
) {
759 lspa
= pcep_obj_create_lspa(
760 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1],
761 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1],
762 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1],
763 DEFAULT_LSAP_SETUP_PRIO
, DEFAULT_LSAP_HOLDING_PRIO
,
764 DEFAULT_LSAP_LOCAL_PRETECTION
);
765 assert(lspa
!= NULL
);
766 lspa
->header
.flag_p
= true;
767 dll_append(objs
, lspa
);
770 /* Bandwidth Objects */
771 if (path
->has_bandwidth
) {
772 /* Requested Bandwidth */
773 bandwidth
= pcep_obj_create_bandwidth(path
->bandwidth
);
774 assert(bandwidth
!= NULL
);
775 bandwidth
->header
.flag_p
= path
->enforce_bandwidth
;
776 dll_append(objs
, bandwidth
);
780 for (struct path_metric
*m
= path
->first_metric
; m
!= NULL
;
782 metric
= pcep_obj_create_metric(m
->type
, m
->is_bound
,
783 m
->is_computed
, m
->value
);
784 assert(metric
!= NULL
);
785 metric
->header
.flag_p
= m
->enforce
;
786 dll_append(objs
, metric
);
790 void pcep_lib_parse_open(struct pcep_caps
*caps
, struct pcep_object_open
*open
)
792 double_linked_list
*tlvs
= open
->header
.tlv_list
;
793 double_linked_list_node
*node
;
794 struct pcep_object_tlv_header
*tlv_header
;
796 caps
->is_stateful
= false;
797 caps
->supported_ofs_are_known
= false;
798 caps
->supported_ofs
= 0;
800 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
801 tlv_header
= (struct pcep_object_tlv_header
*)node
->data
;
802 switch (tlv_header
->type
) {
803 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
804 pcep_lib_parse_open_pce_capability(caps
, tlv_header
);
806 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
808 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
809 pcep_lib_parse_open_objfun_list(caps
, tlv_header
);
812 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
813 "Unexpected OPEN's TLV %s (%u)",
814 pcep_tlv_type_name(tlv_header
->type
),
821 void pcep_lib_parse_open_pce_capability(
822 struct pcep_caps
*caps
, struct pcep_object_tlv_header
*tlv_header
)
824 struct pcep_object_tlv_stateful_pce_capability
*tlv
;
825 tlv
= (struct pcep_object_tlv_stateful_pce_capability
*)tlv_header
;
826 caps
->is_stateful
= tlv
->flag_u_lsp_update_capability
;
829 void pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
830 struct pcep_object_tlv_header
*tlv_header
)
832 double_linked_list_node
*node
;
833 struct pcep_object_tlv_of_list
*tlv
;
834 tlv
= (struct pcep_object_tlv_of_list
*)tlv_header
;
836 caps
->supported_ofs_are_known
= true;
837 for (node
= tlv
->of_list
->head
; node
!= NULL
; node
= node
->next_node
) {
838 of_code
= *(uint16_t *)node
->data
;
841 "Ignoring unexpected objective function with code %u",
845 SET_FLAG(caps
->supported_ofs
, of_code
);
849 void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
)
851 double_linked_list
*tlvs
= rp
->header
.tlv_list
;
852 double_linked_list_node
*node
;
853 struct pcep_object_tlv_header
*tlv
;
855 /* We ignore the other flags and priority for now */
856 path
->req_id
= rp
->request_id
;
857 path
->has_pce_objfun
= false;
858 path
->pce_objfun
= OBJFUN_UNDEFINED
;
860 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
861 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
863 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
864 // TODO: enforce the path setup type is SR_TE_PST
867 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
868 "Unexpected RP's TLV %s (%u)",
869 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
875 void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
)
877 double_linked_list
*tlvs
= srp
->header
.tlv_list
;
878 double_linked_list_node
*node
;
879 struct pcep_object_tlv_header
*tlv
;
881 path
->do_remove
= srp
->flag_lsp_remove
;
882 path
->srp_id
= srp
->srp_id_number
;
884 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
885 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
887 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
888 // TODO: enforce the path setup type is SR_TE_PST
891 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
892 "Unexpected SRP's TLV %s (%u)",
893 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
899 void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
)
901 double_linked_list
*tlvs
= lsp
->header
.tlv_list
;
902 double_linked_list_node
*node
;
903 struct pcep_object_tlv_header
*tlv
;
905 path
->plsp_id
= lsp
->plsp_id
;
906 path
->status
= lsp
->operational_status
;
907 path
->go_active
= lsp
->flag_a
;
908 path
->was_created
= lsp
->flag_c
;
909 path
->was_removed
= lsp
->flag_r
;
910 path
->is_synching
= lsp
->flag_s
;
911 path
->is_delegated
= lsp
->flag_d
;
916 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
917 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
920 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
921 "Unexpected LSP TLV %s (%u)",
922 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
928 void pcep_lib_parse_lspa(struct path
*path
, struct pcep_object_lspa
*lspa
)
930 path
->has_affinity_filters
= true;
931 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
932 lspa
->lspa_exclude_any
;
933 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
934 lspa
->lspa_include_any
;
935 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
936 lspa
->lspa_include_all
;
939 void pcep_lib_parse_metric(struct path
*path
, struct pcep_object_metric
*obj
)
941 struct path_metric
*metric
;
943 metric
= pcep_new_metric();
944 metric
->type
= obj
->type
;
945 metric
->is_bound
= obj
->flag_b
;
946 metric
->is_computed
= obj
->flag_c
;
947 metric
->value
= obj
->value
;
948 metric
->next
= path
->first_metric
;
949 path
->first_metric
= metric
;
952 void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
)
954 struct path_hop
*hop
= NULL
;
955 double_linked_list
*objs
= ero
->sub_objects
;
956 double_linked_list_node
*node
;
957 struct pcep_object_ro_subobj
*obj
;
959 for (node
= objs
->tail
; node
!= NULL
; node
= node
->prev_node
) {
960 obj
= (struct pcep_object_ro_subobj
*)node
->data
;
961 switch (obj
->ro_subobj_type
) {
962 case RO_SUBOBJ_TYPE_SR
:
963 hop
= pcep_lib_parse_ero_sr(
964 hop
, (struct pcep_ro_subobj_sr
*)obj
);
967 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ
,
968 "Unexpected ERO sub-object %s (%u)",
969 pcep_ro_type_name(obj
->ro_subobj_type
),
970 obj
->ro_subobj_type
);
975 path
->first_hop
= hop
;
978 struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
979 struct pcep_ro_subobj_sr
*sr
)
981 struct path_hop
*hop
= NULL
;
984 /* Only support IPv4 node with SID */
988 sid
.mpls
= (struct sid_mpls
){
989 .label
= GET_SR_ERO_SID_LABEL(sr
->sid
),
990 .traffic_class
= GET_SR_ERO_SID_TC(sr
->sid
),
991 .is_bottom
= GET_SR_ERO_SID_S(sr
->sid
),
992 .ttl
= GET_SR_ERO_SID_TTL(sr
->sid
)};
997 hop
= pcep_new_hop();
998 *hop
= (struct path_hop
){.next
= next
,
1000 sr
->ro_subobj
.flag_subobj_loose_hop
,
1001 .has_sid
= !sr
->flag_s
,
1002 .is_mpls
= sr
->flag_m
,
1003 .has_attribs
= sr
->flag_c
,
1005 .has_nai
= !sr
->flag_f
,
1006 .nai
= {.type
= sr
->nai_type
}};
1009 assert(sr
->nai_list
!= NULL
);
1010 double_linked_list_node
*n
= sr
->nai_list
->head
;
1012 assert(n
->data
!= NULL
);
1013 switch (sr
->nai_type
) {
1014 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
1015 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1016 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1017 sizeof(struct in_addr
));
1019 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
1020 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1021 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1022 sizeof(struct in6_addr
));
1024 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
1025 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1026 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1027 sizeof(struct in_addr
));
1030 assert(n
->data
!= NULL
);
1031 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1032 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1033 sizeof(struct in_addr
));
1035 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
1036 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1037 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1038 sizeof(struct in6_addr
));
1041 assert(n
->data
!= NULL
);
1042 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V6
;
1043 memcpy(&hop
->nai
.remote_addr
.ipaddr_v6
, n
->data
,
1044 sizeof(struct in6_addr
));
1046 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
1047 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1048 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1049 sizeof(struct in_addr
));
1052 assert(n
->data
!= NULL
);
1053 hop
->nai
.local_iface
= *(uint32_t *)n
->data
;
1056 assert(n
->data
!= NULL
);
1057 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1058 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1059 sizeof(struct in_addr
));
1062 assert(n
->data
!= NULL
);
1063 hop
->nai
.remote_iface
= *(uint32_t *)n
->data
;
1066 hop
->has_nai
= false;
1067 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI
,
1068 "Unexpected SR segment NAI type %s (%u)",
1069 pcep_nai_type_name(sr
->nai_type
),
1078 struct counters_group
*copy_counter_group(struct counters_group
*from
)
1081 struct counters_group
*result
;
1084 assert(from
->max_subgroups
>= from
->num_subgroups
);
1085 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1086 memcpy(result
, from
, sizeof(*result
));
1087 size
= sizeof(struct counters_subgroup
*) * (from
->max_subgroups
+ 1);
1088 result
->subgroups
= XCALLOC(MTYPE_PCEP
, size
);
1089 for (i
= 0; i
<= from
->max_subgroups
; i
++)
1090 result
->subgroups
[i
] =
1091 copy_counter_subgroup(from
->subgroups
[i
]);
1095 struct counters_subgroup
*copy_counter_subgroup(struct counters_subgroup
*from
)
1098 struct counters_subgroup
*result
;
1101 assert(from
->max_counters
>= from
->num_counters
);
1102 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1103 memcpy(result
, from
, sizeof(*result
));
1104 size
= sizeof(struct counter
*) * (from
->max_counters
+ 1);
1105 result
->counters
= XCALLOC(MTYPE_PCEP
, size
);
1106 for (i
= 0; i
<= from
->max_counters
; i
++)
1107 result
->counters
[i
] = copy_counter(from
->counters
[i
]);
1111 struct counter
*copy_counter(struct counter
*from
)
1113 struct counter
*result
;
1116 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1117 memcpy(result
, from
, sizeof(*result
));
1121 void free_counter_group(struct counters_group
*group
)
1126 for (i
= 0; i
<= group
->max_subgroups
; i
++)
1127 free_counter_subgroup(group
->subgroups
[i
]);
1128 XFREE(MTYPE_PCEP
, group
->subgroups
);
1129 XFREE(MTYPE_PCEP
, group
);
1132 void free_counter_subgroup(struct counters_subgroup
*subgroup
)
1135 if (subgroup
== NULL
)
1137 for (i
= 0; i
<= subgroup
->max_counters
; i
++)
1138 free_counter(subgroup
->counters
[i
]);
1139 XFREE(MTYPE_PCEP
, subgroup
->counters
);
1140 XFREE(MTYPE_PCEP
, subgroup
);
1143 void free_counter(struct counter
*counter
)
1145 if (counter
== NULL
)
1147 XFREE(MTYPE_PCEP
, counter
);