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
);
43 /* Socket callbacks */
44 static int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
46 static int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
48 static int pcep_lib_socket_read_ready(struct thread
*thread
);
49 static int pcep_lib_socket_write_ready(struct thread
*thread
);
51 /* pceplib pcep_event callbacks */
52 static void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
);
54 /* pceplib pthread creation callback */
55 static int pcep_lib_pthread_create_cb(pthread_t
*pthread_id
,
56 const pthread_attr_t
*attr
,
57 void *(*start_routine
)(void *),
58 void *data
, const char *thread_name
);
59 void *pcep_lib_pthread_start_passthrough(void *data
);
60 int pcep_lib_pthread_stop_cb(struct frr_pthread
*, void **);
62 /* Internal functions */
63 static double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
65 static void pcep_lib_format_constraints(struct path
*path
,
66 double_linked_list
*objs
);
67 static void pcep_lib_parse_open(struct pcep_caps
*caps
,
68 struct pcep_object_open
*open
);
70 pcep_lib_parse_open_pce_capability(struct pcep_caps
*caps
,
71 struct pcep_object_tlv_header
*tlv_header
);
73 pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
74 struct pcep_object_tlv_header
*tlv_header
);
75 static void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
);
76 static void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
);
77 static void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
);
78 static void pcep_lib_parse_lspa(struct path
*path
,
79 struct pcep_object_lspa
*lspa
);
80 static void pcep_lib_parse_lsp_symbolic_name(
81 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
);
82 static void pcep_lib_parse_metric(struct path
*path
,
83 struct pcep_object_metric
*obj
);
85 pcep_lib_parse_endpoints_ipv4(struct path
*path
,
86 struct pcep_object_endpoints_ipv4
*obj
);
88 pcep_lib_parse_endpoints_ipv6(struct path
*path
,
89 struct pcep_object_endpoints_ipv6
*obj
);
90 static void pcep_lib_parse_vendor_info(struct path
*path
,
91 struct pcep_object_vendor_info
*obj
);
92 static void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
);
93 static struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
94 struct pcep_ro_subobj_sr
*sr
);
95 static struct counters_group
*copy_counter_group(struct counters_group
*from
);
96 static struct counters_subgroup
*
97 copy_counter_subgroup(struct counters_subgroup
*from
);
98 static struct counter
*copy_counter(struct counter
*from
);
99 static void free_counter_group(struct counters_group
*group
);
100 static void free_counter_subgroup(struct counters_subgroup
*subgroup
);
101 static void free_counter(struct counter
*counter
);
103 struct pcep_lib_pthread_passthrough_data
{
104 void *(*start_routine
)(void *data
);
108 /* ------------ API Functions ------------ */
110 int pcep_lib_initialize(struct frr_pthread
*fpt
)
112 PCEP_DEBUG("Initializing pceplib");
114 /* Register pceplib logging callback */
115 register_logger(pceplib_logging_cb
);
117 /* Its ok that this object goes out of scope, as it
118 * wont be stored, and its values will be copied */
119 struct pceplib_infra_config infra
= {
120 /* Memory infrastructure */
121 .pceplib_infra_mt
= MTYPE_PCEPLIB_INFRA
,
122 .pceplib_messages_mt
= MTYPE_PCEPLIB_MESSAGES
,
123 .malloc_func
= (pceplib_malloc_func
)qmalloc
,
124 .calloc_func
= (pceplib_calloc_func
)qcalloc
,
125 .realloc_func
= (pceplib_realloc_func
)qrealloc
,
126 .strdup_func
= (pceplib_strdup_func
)qstrdup
,
127 .free_func
= (pceplib_free_func
)qfree
,
128 /* Timers infrastructure */
129 .external_infra_data
= fpt
,
130 .socket_read_func
= pcep_lib_pceplib_socket_read_cb
,
131 .socket_write_func
= pcep_lib_pceplib_socket_write_cb
,
133 .pcep_event_func
= pcep_lib_pceplib_event_cb
,
134 /* PCEPlib pthread creation callback */
135 .pthread_create_func
= pcep_lib_pthread_create_cb
};
136 if (!initialize_pcc_infra(&infra
)) {
137 flog_err(EC_PATH_PCEP_PCC_INIT
, "failed to initialize pceplib");
144 void pcep_lib_finalize(void)
146 PCEP_DEBUG("Finalizing pceplib");
147 if (!destroy_pcc()) {
148 flog_err(EC_PATH_PCEP_PCC_FINI
, "failed to finalize pceplib");
154 pcep_lib_connect(struct ipaddr
*src_addr
, int src_port
, struct ipaddr
*dst_addr
,
155 int dst_port
, short msd
,
156 const struct pcep_config_group_opts
*pcep_options
)
158 pcep_configuration
*config
;
161 config
= create_default_pcep_configuration();
162 config
->dst_pcep_port
= dst_port
;
163 config
->src_pcep_port
= src_port
;
164 if (IS_IPADDR_V6(src_addr
)) {
165 config
->is_src_ipv6
= true;
166 memcpy(&config
->src_ip
.src_ipv6
, &src_addr
->ipaddr_v6
,
167 sizeof(struct in6_addr
));
169 config
->is_src_ipv6
= false;
170 config
->src_ip
.src_ipv4
= src_addr
->ipaddr_v4
;
173 config
->support_stateful_pce_lsp_update
= true;
174 config
->support_pce_lsp_instantiation
= pcep_options
->pce_initiated
;
175 config
->support_include_db_version
= false;
176 config
->support_lsp_triggered_resync
= false;
177 config
->support_lsp_delta_sync
= false;
178 config
->support_pce_triggered_initial_sync
= false;
179 config
->support_sr_te_pst
= true;
180 config
->pcc_can_resolve_nai_to_sid
= false;
182 config
->max_sid_depth
= msd
;
183 config
->pcep_msg_versioning
->draft_ietf_pce_segment_routing_07
=
184 pcep_options
->draft07
;
185 config
->keep_alive_seconds
= pcep_options
->keep_alive_seconds
;
186 config
->min_keep_alive_seconds
= pcep_options
->min_keep_alive_seconds
;
187 config
->max_keep_alive_seconds
= pcep_options
->max_keep_alive_seconds
;
188 config
->dead_timer_seconds
= pcep_options
->dead_timer_seconds
;
189 config
->min_dead_timer_seconds
= pcep_options
->min_dead_timer_seconds
;
190 config
->max_dead_timer_seconds
= pcep_options
->max_dead_timer_seconds
;
191 config
->request_time_seconds
= pcep_options
->pcep_request_time_seconds
;
192 /* TODO when available in the pceplib, set it here
193 pcep_options->state_timeout_inteval_seconds;*/
195 if (pcep_options
->tcp_md5_auth
[0] != '\0') {
196 config
->is_tcp_auth_md5
= true;
197 strlcpy(config
->tcp_authentication_str
,
198 pcep_options
->tcp_md5_auth
,
199 sizeof(config
->tcp_authentication_str
));
201 config
->is_tcp_auth_md5
= false;
204 if (IS_IPADDR_V6(dst_addr
)) {
205 sess
= connect_pce_ipv6(config
, &dst_addr
->ipaddr_v6
);
207 sess
= connect_pce(config
, &dst_addr
->ipaddr_v4
);
209 destroy_pcep_configuration(config
);
213 void pcep_lib_disconnect(pcep_session
*sess
)
215 assert(sess
!= NULL
);
216 disconnect_pce(sess
);
219 /* Callback passed to pceplib to write to a socket.
220 * When the socket is ready to be written to,
221 * pcep_lib_socket_write_ready() will be called */
223 int pcep_lib_pceplib_socket_write_cb(void *fpt
, void **thread
, int fd
,
226 return pcep_thread_socket_write(fpt
, thread
, fd
, payload
,
227 pcep_lib_socket_write_ready
);
230 /* Callback passed to pceplib to read from a socket.
231 * When the socket is ready to be read from,
232 * pcep_lib_socket_read_ready() will be called */
234 int pcep_lib_pceplib_socket_read_cb(void *fpt
, void **thread
, int fd
,
237 return pcep_thread_socket_read(fpt
, thread
, fd
, payload
,
238 pcep_lib_socket_read_ready
);
241 /* Callbacks called by path_pcep_controller when a socket is ready to read/write
244 int pcep_lib_socket_write_ready(struct thread
*thread
)
246 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
247 assert(data
!= NULL
);
249 int retval
= pceplib_external_socket_write(data
->fd
, data
->payload
);
250 XFREE(MTYPE_PCEP
, data
);
255 int pcep_lib_socket_read_ready(struct thread
*thread
)
257 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
258 assert(data
!= NULL
);
260 int retval
= pceplib_external_socket_read(data
->fd
, data
->payload
);
261 XFREE(MTYPE_PCEP
, data
);
266 /* Callback passed to pceplib when a pcep_event is ready */
267 void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
)
269 pcep_thread_send_ctrl_event(fpt
, event
, pcep_thread_pcep_event
);
272 /* Wrapper function around the actual pceplib thread start function */
273 void *pcep_lib_pthread_start_passthrough(void *data
)
275 struct frr_pthread
*fpt
= data
;
276 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= fpt
->data
;
277 void *start_routine_data
= passthrough_data
->data
;
278 void *(*start_routine
)(void *) = passthrough_data
->start_routine
;
279 XFREE(MTYPE_PCEP
, passthrough_data
);
281 if (start_routine
!= NULL
) {
282 return start_routine(start_routine_data
);
288 int pcep_lib_pthread_create_cb(pthread_t
*thread_id
, const pthread_attr_t
*attr
,
289 void *(*start_routine
)(void *), void *data
,
290 const char *thread_name
)
292 /* Since FRR calls the start_routine with a struct frr_pthread,
293 * we have to store the real data and callback in a passthrough
294 * and pass the actual data the start_routine needs */
295 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= XMALLOC(
296 MTYPE_PCEP
, sizeof(struct pcep_lib_pthread_passthrough_data
));
297 passthrough_data
->data
= data
;
298 passthrough_data
->start_routine
= start_routine
;
300 struct frr_pthread_attr fpt_attr
= {
301 .start
= pcep_lib_pthread_start_passthrough
,
302 .stop
= pcep_lib_pthread_stop_cb
};
303 struct frr_pthread
*fpt
=
304 frr_pthread_new(&fpt_attr
, thread_name
, "pcep_lib");
309 fpt
->data
= passthrough_data
;
310 int retval
= frr_pthread_run(fpt
, attr
);
315 *thread_id
= fpt
->thread
;
320 int pcep_lib_pthread_stop_cb(struct frr_pthread
*fpt
, void **res
)
323 frr_pthread_destroy(fpt
);
328 struct pcep_message
*pcep_lib_format_report(struct pcep_caps
*caps
,
331 double_linked_list
*objs
= pcep_lib_format_path(caps
, path
);
332 return pcep_msg_create_report(objs
);
335 static struct pcep_object_rp
*create_rp(uint32_t reqid
)
337 double_linked_list
*rp_tlvs
;
338 struct pcep_object_tlv_path_setup_type
*setup_type_tlv
;
339 struct pcep_object_rp
*rp
;
341 rp_tlvs
= dll_initialize();
342 setup_type_tlv
= pcep_tlv_create_path_setup_type(SR_TE_PST
);
343 dll_append(rp_tlvs
, setup_type_tlv
);
345 rp
= pcep_obj_create_rp(0, false, false, false, true, reqid
, rp_tlvs
);
350 struct pcep_message
*pcep_lib_format_request(struct pcep_caps
*caps
,
353 struct ipaddr
*src
= &path
->pcc_addr
;
354 struct ipaddr
*dst
= &path
->nbkey
.endpoint
;
355 double_linked_list
*objs
;
356 struct pcep_object_rp
*rp
;
357 struct pcep_object_endpoints_ipv4
*endpoints_ipv4
;
358 struct pcep_object_endpoints_ipv6
*endpoints_ipv6
;
359 struct pcep_object_objective_function
*of
= NULL
;
360 enum objfun_type objfun
= OBJFUN_UNDEFINED
;
362 assert(src
->ipa_type
== dst
->ipa_type
);
364 objs
= dll_initialize();
365 rp
= create_rp(path
->req_id
);
366 rp
->header
.flag_p
= true;
368 pcep_lib_format_constraints(path
, objs
);
370 /* Objective Function */
371 if (path
->has_pcc_objfun
) {
372 objfun
= path
->pcc_objfun
;
375 if (objfun
!= OBJFUN_UNDEFINED
) {
376 of
= pcep_obj_create_objective_function(objfun
, NULL
);
378 of
->header
.flag_p
= path
->enforce_pcc_objfun
;
379 dll_append(objs
, of
);
382 if (IS_IPADDR_V6(src
)) {
383 endpoints_ipv6
= pcep_obj_create_endpoint_ipv6(&src
->ipaddr_v6
,
385 endpoints_ipv6
->header
.flag_p
= true;
386 return pcep_msg_create_request_ipv6(rp
, endpoints_ipv6
, objs
);
388 endpoints_ipv4
= pcep_obj_create_endpoint_ipv4(&src
->ipaddr_v4
,
390 endpoints_ipv4
->header
.flag_p
= true;
391 return pcep_msg_create_request(rp
, endpoints_ipv4
, objs
);
395 struct pcep_message
*pcep_lib_format_error(int error_type
, int error_value
,
398 double_linked_list
*objs
, *srp_tlvs
;
399 struct pcep_object_srp
*srp
;
400 struct pcep_object_tlv_header
*tlv
;
402 if ((path
== NULL
) || (path
->srp_id
== 0))
403 return pcep_msg_create_error(error_type
, error_value
);
405 objs
= dll_initialize();
406 srp_tlvs
= dll_initialize();
407 tlv
= (struct pcep_object_tlv_header
*)pcep_tlv_create_path_setup_type(
409 dll_append(srp_tlvs
, tlv
);
410 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
, srp_tlvs
);
411 dll_append(objs
, srp
);
412 return pcep_msg_create_error_with_objects(error_type
, error_value
,
416 struct pcep_message
*pcep_lib_format_request_cancelled(uint32_t reqid
)
418 struct pcep_object_notify
*notify
;
419 double_linked_list
*objs
;
420 struct pcep_object_rp
*rp
;
422 notify
= pcep_obj_create_notify(
423 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED
,
424 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST
);
425 objs
= dll_initialize();
426 rp
= create_rp(reqid
);
427 dll_append(objs
, rp
);
429 return pcep_msg_create_notify(notify
, objs
);
432 struct path
*pcep_lib_parse_path(struct pcep_message
*msg
)
435 double_linked_list
*objs
= msg
->obj_list
;
436 double_linked_list_node
*node
;
438 struct pcep_object_header
*obj
;
439 struct pcep_object_rp
*rp
= NULL
;
440 struct pcep_object_srp
*srp
= NULL
;
441 struct pcep_object_lsp
*lsp
= NULL
;
442 struct pcep_object_lspa
*lspa
= NULL
;
443 struct pcep_object_ro
*ero
= NULL
;
444 struct pcep_object_metric
*metric
= NULL
;
445 struct pcep_object_bandwidth
*bandwidth
= NULL
;
446 struct pcep_object_objective_function
*of
= NULL
;
447 struct pcep_object_endpoints_ipv4
*epv4
= NULL
;
448 struct pcep_object_endpoints_ipv6
*epv6
= NULL
;
449 struct pcep_object_vendor_info
*vendor_info
= NULL
;
451 path
= pcep_new_path();
453 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
454 obj
= (struct pcep_object_header
*)node
->data
;
455 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
456 case CLASS_TYPE(PCEP_OBJ_CLASS_RP
, PCEP_OBJ_TYPE_RP
):
458 rp
= (struct pcep_object_rp
*)obj
;
459 pcep_lib_parse_rp(path
, rp
);
461 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_TYPE_SRP
):
463 srp
= (struct pcep_object_srp
*)obj
;
464 pcep_lib_parse_srp(path
, srp
);
466 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP
, PCEP_OBJ_TYPE_LSP
):
467 /* Only support single LSP per message */
469 lsp
= (struct pcep_object_lsp
*)obj
;
470 pcep_lib_parse_lsp(path
, lsp
);
472 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA
, PCEP_OBJ_TYPE_LSPA
):
473 assert(lspa
== NULL
);
474 lspa
= (struct pcep_object_lspa
*)obj
;
475 pcep_lib_parse_lspa(path
, lspa
);
477 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO
, PCEP_OBJ_TYPE_ERO
):
478 /* Only support single ERO per message */
480 ero
= (struct pcep_object_ro
*)obj
;
481 pcep_lib_parse_ero(path
, ero
);
483 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC
, PCEP_OBJ_TYPE_METRIC
):
484 metric
= (struct pcep_object_metric
*)obj
;
485 pcep_lib_parse_metric(path
, metric
);
487 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
488 PCEP_OBJ_TYPE_BANDWIDTH_REQ
):
489 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
490 PCEP_OBJ_TYPE_BANDWIDTH_CISCO
):
491 bandwidth
= (struct pcep_object_bandwidth
*)obj
;
492 path
->has_bandwidth
= true;
493 path
->bandwidth
= bandwidth
->bandwidth
;
495 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH
, PCEP_OBJ_TYPE_NOPATH
):
496 path
->no_path
= true;
498 case CLASS_TYPE(PCEP_OBJ_CLASS_OF
, PCEP_OBJ_TYPE_OF
):
499 of
= (struct pcep_object_objective_function
*)obj
;
500 path
->has_pce_objfun
= true;
501 path
->pce_objfun
= of
->of_code
;
503 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
504 PCEP_OBJ_TYPE_ENDPOINT_IPV4
):
505 epv4
= (struct pcep_object_endpoints_ipv4
*)obj
;
506 pcep_lib_parse_endpoints_ipv4(path
, epv4
);
508 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
509 PCEP_OBJ_TYPE_ENDPOINT_IPV6
):
510 epv6
= (struct pcep_object_endpoints_ipv6
*)obj
;
511 pcep_lib_parse_endpoints_ipv6(path
, epv6
);
513 case CLASS_TYPE(PCEP_OBJ_CLASS_VENDOR_INFO
,
514 PCEP_OBJ_TYPE_VENDOR_INFO
):
515 vendor_info
= (struct pcep_object_vendor_info
*)obj
;
516 pcep_lib_parse_vendor_info(path
, vendor_info
);
519 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
520 "Unexpected PCEP object %s (%u) / %s (%u)",
521 pcep_object_class_name(obj
->object_class
),
523 pcep_object_type_name(obj
->object_class
,
533 void pcep_lib_parse_capabilities(struct pcep_message
*msg
,
534 struct pcep_caps
*caps
)
536 double_linked_list
*objs
= msg
->obj_list
;
537 double_linked_list_node
*node
;
539 struct pcep_object_header
*obj
;
540 struct pcep_object_open
*open
= NULL
;
542 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
543 obj
= (struct pcep_object_header
*)node
->data
;
544 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
545 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN
, PCEP_OBJ_TYPE_OPEN
):
546 assert(open
== NULL
);
547 open
= (struct pcep_object_open
*)obj
;
548 pcep_lib_parse_open(caps
, open
);
551 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
552 "Unexpected PCEP object %s (%u) / %s (%u)",
553 pcep_object_class_name(obj
->object_class
),
555 pcep_object_type_name(obj
->object_class
,
563 struct counters_group
*pcep_lib_copy_counters(pcep_session
*sess
)
565 if (!sess
|| !sess
->pcep_session_counters
) {
569 return copy_counter_group(sess
->pcep_session_counters
);
572 void pcep_lib_free_counters(struct counters_group
*counters
)
574 free_counter_group(counters
);
577 pcep_session
*pcep_lib_copy_pcep_session(pcep_session
*sess
)
584 copy
= XCALLOC(MTYPE_PCEP
, sizeof(*copy
));
585 memcpy(copy
, sess
, sizeof(*copy
));
586 /* These fields should not be accessed */
587 copy
->num_unknown_messages_time_queue
= NULL
;
588 copy
->socket_comm_session
= NULL
;
589 copy
->pcep_session_counters
= NULL
;
594 /* ------------ pceplib logging callback ------------ */
596 int pceplib_logging_cb(int priority
, const char *fmt
, va_list args
)
599 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
600 PCEP_DEBUG_PCEPLIB(priority
, "pceplib: %s", buffer
);
604 /* ------------ Internal Functions ------------ */
606 double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
609 struct in_addr addr_null
;
610 double_linked_list
*objs
, *srp_tlvs
, *lsp_tlvs
, *ero_objs
;
611 struct pcep_object_tlv_header
*tlv
;
612 struct pcep_object_ro_subobj
*ero_obj
;
613 struct pcep_object_srp
*srp
;
614 struct pcep_object_lsp
*lsp
;
615 struct pcep_object_ro
*ero
;
616 uint32_t encoded_binding_sid
;
617 char binding_sid_lsp_tlv_data
[6];
619 memset(&addr_null
, 0, sizeof(addr_null
));
621 objs
= dll_initialize();
623 if (path
->plsp_id
!= 0) {
625 srp_tlvs
= dll_initialize();
626 tlv
= (struct pcep_object_tlv_header
*)
627 pcep_tlv_create_path_setup_type(SR_TE_PST
);
629 dll_append(srp_tlvs
, tlv
);
630 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
,
633 srp
->header
.flag_p
= true;
634 dll_append(objs
, srp
);
638 lsp_tlvs
= dll_initialize();
640 if (path
->plsp_id
== 0 || IS_IPADDR_NONE(&path
->nbkey
.endpoint
)
641 || IS_IPADDR_NONE(&path
->pcc_addr
)) {
642 tlv
= (struct pcep_object_tlv_header
*)
643 pcep_tlv_create_ipv4_lsp_identifiers(
644 &addr_null
, &addr_null
, 0, 0, &addr_null
);
646 assert(path
->pcc_addr
.ipa_type
647 == path
->nbkey
.endpoint
.ipa_type
);
648 if (IS_IPADDR_V4(&path
->pcc_addr
)) {
649 tlv
= (struct pcep_object_tlv_header
*)
650 pcep_tlv_create_ipv4_lsp_identifiers(
651 &path
->pcc_addr
.ipaddr_v4
,
652 &path
->nbkey
.endpoint
.ipaddr_v4
, 0, 0,
653 &path
->pcc_addr
.ipaddr_v4
);
655 tlv
= (struct pcep_object_tlv_header
*)
656 pcep_tlv_create_ipv6_lsp_identifiers(
657 &path
->pcc_addr
.ipaddr_v6
,
658 &path
->nbkey
.endpoint
.ipaddr_v6
, 0, 0,
659 &path
->pcc_addr
.ipaddr_v6
);
663 dll_append(lsp_tlvs
, tlv
);
664 if (path
->name
!= NULL
) {
665 tlv
= (struct pcep_object_tlv_header
*)
666 /*FIXME: Remove the typecasty when pceplib is changed
667 to take a const char* */
668 pcep_tlv_create_symbolic_path_name((char *)path
->name
,
671 dll_append(lsp_tlvs
, tlv
);
673 if ((path
->plsp_id
!= 0) && (path
->binding_sid
!= MPLS_LABEL_NONE
)) {
674 memset(binding_sid_lsp_tlv_data
, 0, 2);
675 encoded_binding_sid
= htonl(path
->binding_sid
<< 12);
676 memcpy(binding_sid_lsp_tlv_data
+ 2, &encoded_binding_sid
, 4);
677 tlv
= (struct pcep_object_tlv_header
*)
678 pcep_tlv_create_tlv_arbitrary(
679 binding_sid_lsp_tlv_data
,
680 sizeof(binding_sid_lsp_tlv_data
),
681 PCEP_OBJ_TYPE_CISCO_BSID
);
683 dll_append(lsp_tlvs
, tlv
);
685 lsp
= pcep_obj_create_lsp(
686 path
->plsp_id
, path
->status
, path
->was_created
/* C Flag */,
687 path
->go_active
/* A Flag */, path
->was_removed
/* R Flag */,
688 path
->is_synching
/* S Flag */, path
->is_delegated
/* D Flag */,
691 lsp
->header
.flag_p
= true;
692 dll_append(objs
, lsp
);
694 ero_objs
= dll_initialize();
695 for (struct path_hop
*hop
= path
->first_hop
; hop
!= NULL
;
699 /* Only supporting MPLS hops with both sid and nai */
700 assert(hop
->is_mpls
);
701 assert(hop
->has_sid
);
703 if (hop
->has_attribs
) {
704 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
,
705 hop
->sid
.mpls
.traffic_class
,
706 hop
->sid
.mpls
.is_bottom
,
709 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
, 0, 0, 0);
714 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_ABSENT
);
716 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
);
717 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_UNKNOWN
);
718 switch (hop
->nai
.type
) {
719 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
720 ero_obj
= (struct pcep_object_ro_subobj
*)
721 pcep_obj_create_ro_subobj_sr_ipv4_node(
722 hop
->is_loose
, !hop
->has_sid
,
723 hop
->has_attribs
, /* C Flag */
724 hop
->is_mpls
, /* M Flag */
726 &hop
->nai
.local_addr
.ipaddr_v4
);
728 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
729 ero_obj
= (struct pcep_object_ro_subobj
*)
730 pcep_obj_create_ro_subobj_sr_ipv6_node(
731 hop
->is_loose
, !hop
->has_sid
,
732 hop
->has_attribs
, /* C Flag */
733 hop
->is_mpls
, /* M Flag */
735 &hop
->nai
.local_addr
.ipaddr_v6
);
737 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
738 ero_obj
= (struct pcep_object_ro_subobj
*)
739 pcep_obj_create_ro_subobj_sr_ipv4_adj(
740 hop
->is_loose
, !hop
->has_sid
,
741 hop
->has_attribs
, /* C Flag */
742 hop
->is_mpls
, /* M Flag */
744 &hop
->nai
.local_addr
.ipaddr_v4
,
745 &hop
->nai
.remote_addr
748 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
749 ero_obj
= (struct pcep_object_ro_subobj
*)
750 pcep_obj_create_ro_subobj_sr_ipv6_adj(
751 hop
->is_loose
, !hop
->has_sid
,
752 hop
->has_attribs
, /* C Flag */
753 hop
->is_mpls
, /* M Flag */
755 &hop
->nai
.local_addr
.ipaddr_v6
,
756 &hop
->nai
.remote_addr
759 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
760 ero_obj
= (struct pcep_object_ro_subobj
*)
761 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
762 hop
->is_loose
, !hop
->has_sid
,
763 hop
->has_attribs
, /* C Flag */
764 hop
->is_mpls
, /* M Flag */
766 hop
->nai
.local_addr
.ipaddr_v4
768 hop
->nai
.local_iface
,
769 hop
->nai
.remote_addr
.ipaddr_v4
771 hop
->nai
.remote_iface
);
777 if (ero_obj
== NULL
) {
778 ero_obj
= (struct pcep_object_ro_subobj
*)
779 pcep_obj_create_ro_subobj_sr_nonai(
781 hop
->has_attribs
, /* C Flag */
782 hop
->is_mpls
); /* M Flag */
784 dll_append(ero_objs
, ero_obj
);
786 ero
= pcep_obj_create_ero(ero_objs
);
788 ero
->header
.flag_p
= true;
789 dll_append(objs
, ero
);
791 if (path
->plsp_id
== 0) {
795 pcep_lib_format_constraints(path
, objs
);
800 void pcep_lib_format_constraints(struct path
*path
, double_linked_list
*objs
)
802 struct pcep_object_metric
*metric
;
803 struct pcep_object_bandwidth
*bandwidth
;
804 struct pcep_object_lspa
*lspa
;
807 if (path
->has_affinity_filters
) {
808 lspa
= pcep_obj_create_lspa(
809 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1],
810 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1],
811 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1],
812 DEFAULT_LSAP_SETUP_PRIO
, DEFAULT_LSAP_HOLDING_PRIO
,
813 DEFAULT_LSAP_LOCAL_PRETECTION
);
814 assert(lspa
!= NULL
);
815 lspa
->header
.flag_p
= true;
816 dll_append(objs
, lspa
);
819 /* Bandwidth Objects */
820 if (path
->has_bandwidth
) {
821 /* Requested Bandwidth */
822 bandwidth
= pcep_obj_create_bandwidth(path
->bandwidth
);
823 assert(bandwidth
!= NULL
);
824 bandwidth
->header
.flag_p
= path
->enforce_bandwidth
;
825 dll_append(objs
, bandwidth
);
829 for (struct path_metric
*m
= path
->first_metric
; m
!= NULL
;
831 metric
= pcep_obj_create_metric(m
->type
, m
->is_bound
,
832 m
->is_computed
, m
->value
);
833 assert(metric
!= NULL
);
834 metric
->header
.flag_p
= m
->enforce
;
835 dll_append(objs
, metric
);
839 void pcep_lib_parse_open(struct pcep_caps
*caps
, struct pcep_object_open
*open
)
841 double_linked_list
*tlvs
= open
->header
.tlv_list
;
842 double_linked_list_node
*node
;
843 struct pcep_object_tlv_header
*tlv_header
;
845 caps
->is_stateful
= false;
846 caps
->supported_ofs_are_known
= false;
847 caps
->supported_ofs
= 0;
849 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
850 tlv_header
= (struct pcep_object_tlv_header
*)node
->data
;
851 switch (tlv_header
->type
) {
852 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
853 pcep_lib_parse_open_pce_capability(caps
, tlv_header
);
855 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
857 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
858 pcep_lib_parse_open_objfun_list(caps
, tlv_header
);
861 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
862 "Unexpected OPEN's TLV %s (%u)",
863 pcep_tlv_type_name(tlv_header
->type
),
870 void pcep_lib_parse_open_pce_capability(
871 struct pcep_caps
*caps
, struct pcep_object_tlv_header
*tlv_header
)
873 struct pcep_object_tlv_stateful_pce_capability
*tlv
;
874 tlv
= (struct pcep_object_tlv_stateful_pce_capability
*)tlv_header
;
875 caps
->is_stateful
= tlv
->flag_u_lsp_update_capability
;
878 void pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
879 struct pcep_object_tlv_header
*tlv_header
)
881 double_linked_list_node
*node
;
882 struct pcep_object_tlv_of_list
*tlv
;
883 tlv
= (struct pcep_object_tlv_of_list
*)tlv_header
;
885 caps
->supported_ofs_are_known
= true;
886 for (node
= tlv
->of_list
->head
; node
!= NULL
; node
= node
->next_node
) {
887 of_code
= *(uint16_t *)node
->data
;
890 "Ignoring unexpected objective function with code %u",
894 SET_FLAG(caps
->supported_ofs
, of_code
);
898 void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
)
900 double_linked_list
*tlvs
= rp
->header
.tlv_list
;
901 double_linked_list_node
*node
;
902 struct pcep_object_tlv_header
*tlv
;
905 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
906 "Unexpected Empty RP's TLV plsp-id:(%d)",
907 path
? (int32_t)path
->plsp_id
: -1);
910 /* We ignore the other flags and priority for now */
911 path
->req_id
= rp
->request_id
;
912 path
->has_pce_objfun
= false;
913 path
->pce_objfun
= OBJFUN_UNDEFINED
;
915 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
916 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
918 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
919 // TODO: enforce the path setup type is SR_TE_PST
922 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
923 "Unexpected RP's TLV %s (%u)",
924 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
930 void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
)
932 double_linked_list
*tlvs
= srp
->header
.tlv_list
;
933 double_linked_list_node
*node
;
934 struct pcep_object_tlv_header
*tlv
;
936 path
->do_remove
= srp
->flag_lsp_remove
;
937 path
->srp_id
= srp
->srp_id_number
;
940 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
941 "Unexpected Empty SRP's TLV plsp-id:(%d)",
942 path
? (int32_t)path
->plsp_id
: -1);
945 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
946 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
948 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
949 // TODO: enforce the path setup type is SR_TE_PST
952 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
953 "Unexpected SRP's TLV %s (%u)",
954 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
960 void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
)
962 double_linked_list
*tlvs
= lsp
->header
.tlv_list
;
963 double_linked_list_node
*node
;
964 struct pcep_object_tlv_header
*tlv
;
965 struct pcep_object_tlv_symbolic_path_name
*name
;
966 struct pcep_object_tlv_arbitrary
*arb_tlv
;
968 path
->plsp_id
= lsp
->plsp_id
;
969 path
->status
= lsp
->operational_status
;
970 path
->go_active
= lsp
->flag_a
;
971 path
->was_created
= lsp
->flag_c
;
972 path
->was_removed
= lsp
->flag_r
;
973 path
->is_synching
= lsp
->flag_s
;
974 path
->is_delegated
= lsp
->flag_d
;
977 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
978 "Unexpected Empty LSP's TLV plsp-id:(%d)",
979 path
? (int32_t)path
->plsp_id
: -1);
983 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
984 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
986 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
987 name
= (struct pcep_object_tlv_symbolic_path_name
*)tlv
;
988 pcep_lib_parse_lsp_symbolic_name(path
, name
);
990 case PCEP_OBJ_TYPE_CISCO_BSID
:
991 arb_tlv
= (struct pcep_object_tlv_arbitrary
*)tlv
;
992 memcpy(&path
->binding_sid
, arb_tlv
->data
+ 2,
993 sizeof(path
->binding_sid
));
994 path
->binding_sid
= ntohl(path
->binding_sid
);
995 path
->binding_sid
= (path
->binding_sid
>> 12);
998 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
999 "Unexpected LSP TLV %s (%u)",
1000 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
1006 void pcep_lib_parse_lsp_symbolic_name(
1007 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
)
1009 uint16_t size
= tlv
->symbolic_path_name_length
;
1010 assert(path
->name
== NULL
);
1011 size
= size
> MAX_PATH_NAME_SIZE
? MAX_PATH_NAME_SIZE
: size
;
1012 path
->name
= XCALLOC(MTYPE_PCEP
, size
);
1013 strlcpy((char *)path
->name
, tlv
->symbolic_path_name
, size
+ 1);
1016 void pcep_lib_parse_lspa(struct path
*path
, struct pcep_object_lspa
*lspa
)
1018 path
->has_affinity_filters
= true;
1019 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
1020 lspa
->lspa_exclude_any
;
1021 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
1022 lspa
->lspa_include_any
;
1023 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
1024 lspa
->lspa_include_all
;
1027 void pcep_lib_parse_metric(struct path
*path
, struct pcep_object_metric
*obj
)
1029 struct path_metric
*metric
;
1031 metric
= pcep_new_metric();
1032 metric
->type
= obj
->type
;
1033 metric
->is_bound
= obj
->flag_b
;
1034 metric
->is_computed
= obj
->flag_c
;
1035 metric
->value
= obj
->value
;
1036 metric
->next
= path
->first_metric
;
1037 path
->first_metric
= metric
;
1040 void pcep_lib_parse_endpoints_ipv4(struct path
*path
,
1041 struct pcep_object_endpoints_ipv4
*obj
)
1043 SET_IPADDR_V4(&path
->pcc_addr
);
1044 path
->pcc_addr
.ipaddr_v4
= obj
->src_ipv4
;
1045 SET_IPADDR_V4(&path
->nbkey
.endpoint
);
1046 path
->nbkey
.endpoint
.ipaddr_v4
= obj
->dst_ipv4
;
1049 void pcep_lib_parse_endpoints_ipv6(struct path
*path
,
1050 struct pcep_object_endpoints_ipv6
*obj
)
1052 SET_IPADDR_V6(&path
->pcc_addr
);
1053 path
->pcc_addr
.ipaddr_v6
= obj
->src_ipv6
;
1054 SET_IPADDR_V6(&path
->nbkey
.endpoint
);
1055 path
->nbkey
.endpoint
.ipaddr_v6
= obj
->dst_ipv6
;
1058 void pcep_lib_parse_vendor_info(struct path
*path
,
1059 struct pcep_object_vendor_info
*obj
)
1061 if (obj
->enterprise_number
== ENTERPRISE_NUMBER_CISCO
1062 && obj
->enterprise_specific_info
== ENTERPRISE_COLOR_CISCO
)
1063 path
->nbkey
.color
= obj
->enterprise_specific_info1
;
1065 path
->nbkey
.color
= 0;
1068 void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
)
1070 struct path_hop
*hop
= NULL
;
1071 double_linked_list
*objs
= ero
->sub_objects
;
1072 double_linked_list_node
*node
;
1073 struct pcep_object_ro_subobj
*obj
;
1076 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1077 "Unexpected Empty ERO's sub_obj plsp-id:(%d)",
1078 path
? (int32_t)path
->plsp_id
: -1);
1081 for (node
= objs
->tail
; node
!= NULL
; node
= node
->prev_node
) {
1082 obj
= (struct pcep_object_ro_subobj
*)node
->data
;
1083 switch (obj
->ro_subobj_type
) {
1084 case RO_SUBOBJ_TYPE_SR
:
1085 hop
= pcep_lib_parse_ero_sr(
1086 hop
, (struct pcep_ro_subobj_sr
*)obj
);
1089 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ
,
1090 "Unexpected ERO sub-object %s (%u)",
1091 pcep_ro_type_name(obj
->ro_subobj_type
),
1092 obj
->ro_subobj_type
);
1097 path
->first_hop
= hop
;
1100 struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
1101 struct pcep_ro_subobj_sr
*sr
)
1103 struct path_hop
*hop
= NULL
;
1106 /* Only support IPv4 node with SID */
1107 assert(!sr
->flag_s
);
1110 sid
.mpls
= (struct sid_mpls
){
1111 .label
= GET_SR_ERO_SID_LABEL(sr
->sid
),
1112 .traffic_class
= GET_SR_ERO_SID_TC(sr
->sid
),
1113 .is_bottom
= GET_SR_ERO_SID_S(sr
->sid
),
1114 .ttl
= GET_SR_ERO_SID_TTL(sr
->sid
)};
1116 sid
.value
= sr
->sid
;
1119 hop
= pcep_new_hop();
1120 *hop
= (struct path_hop
){.next
= next
,
1122 sr
->ro_subobj
.flag_subobj_loose_hop
,
1123 .has_sid
= !sr
->flag_s
,
1124 .is_mpls
= sr
->flag_m
,
1125 .has_attribs
= sr
->flag_c
,
1127 .has_nai
= !sr
->flag_f
,
1128 .nai
= {.type
= sr
->nai_type
}};
1131 assert(sr
->nai_list
!= NULL
);
1132 double_linked_list_node
*n
= sr
->nai_list
->head
;
1134 assert(n
->data
!= NULL
);
1135 switch (sr
->nai_type
) {
1136 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
1137 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1138 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1139 sizeof(struct in_addr
));
1141 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
1142 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1143 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1144 sizeof(struct in6_addr
));
1146 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
1147 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1148 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1149 sizeof(struct in_addr
));
1152 assert(n
->data
!= NULL
);
1153 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1154 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1155 sizeof(struct in_addr
));
1157 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
1158 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1159 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1160 sizeof(struct in6_addr
));
1163 assert(n
->data
!= NULL
);
1164 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V6
;
1165 memcpy(&hop
->nai
.remote_addr
.ipaddr_v6
, n
->data
,
1166 sizeof(struct in6_addr
));
1168 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
1169 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1170 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1171 sizeof(struct in_addr
));
1174 assert(n
->data
!= NULL
);
1175 hop
->nai
.local_iface
= *(uint32_t *)n
->data
;
1178 assert(n
->data
!= NULL
);
1179 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1180 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1181 sizeof(struct in_addr
));
1184 assert(n
->data
!= NULL
);
1185 hop
->nai
.remote_iface
= *(uint32_t *)n
->data
;
1188 hop
->has_nai
= false;
1189 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI
,
1190 "Unexpected SR segment NAI type %s (%u)",
1191 pcep_nai_type_name(sr
->nai_type
),
1200 struct counters_group
*copy_counter_group(struct counters_group
*from
)
1203 struct counters_group
*result
;
1206 assert(from
->max_subgroups
>= from
->num_subgroups
);
1207 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1208 memcpy(result
, from
, sizeof(*result
));
1209 size
= sizeof(struct counters_subgroup
*) * (from
->max_subgroups
+ 1);
1210 result
->subgroups
= XCALLOC(MTYPE_PCEP
, size
);
1211 for (i
= 0; i
<= from
->max_subgroups
; i
++)
1212 result
->subgroups
[i
] =
1213 copy_counter_subgroup(from
->subgroups
[i
]);
1217 struct counters_subgroup
*copy_counter_subgroup(struct counters_subgroup
*from
)
1220 struct counters_subgroup
*result
;
1223 assert(from
->max_counters
>= from
->num_counters
);
1224 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1225 memcpy(result
, from
, sizeof(*result
));
1226 size
= sizeof(struct counter
*) * (from
->max_counters
+ 1);
1227 result
->counters
= XCALLOC(MTYPE_PCEP
, size
);
1228 for (i
= 0; i
<= from
->max_counters
; i
++)
1229 result
->counters
[i
] = copy_counter(from
->counters
[i
]);
1233 struct counter
*copy_counter(struct counter
*from
)
1235 struct counter
*result
;
1238 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1239 memcpy(result
, from
, sizeof(*result
));
1243 void free_counter_group(struct counters_group
*group
)
1248 for (i
= 0; i
<= group
->max_subgroups
; i
++)
1249 free_counter_subgroup(group
->subgroups
[i
]);
1250 XFREE(MTYPE_PCEP
, group
->subgroups
);
1251 XFREE(MTYPE_PCEP
, group
);
1254 void free_counter_subgroup(struct counters_subgroup
*subgroup
)
1257 if (subgroup
== NULL
)
1259 for (i
= 0; i
<= subgroup
->max_counters
; i
++)
1260 free_counter(subgroup
->counters
[i
]);
1261 XFREE(MTYPE_PCEP
, subgroup
->counters
);
1262 XFREE(MTYPE_PCEP
, subgroup
);
1265 void free_counter(struct counter
*counter
)
1267 if (counter
== NULL
)
1269 XFREE(MTYPE_PCEP
, counter
);