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 void pcep_lib_socket_read_ready(struct thread
*thread
);
49 static void 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 void pcep_lib_socket_write_ready(struct thread
*thread
)
246 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
247 assert(data
!= NULL
);
249 pceplib_external_socket_write(data
->fd
, data
->payload
);
250 XFREE(MTYPE_PCEP
, data
);
253 void pcep_lib_socket_read_ready(struct thread
*thread
)
255 struct pcep_ctrl_socket_data
*data
= THREAD_ARG(thread
);
256 assert(data
!= NULL
);
258 pceplib_external_socket_read(data
->fd
, data
->payload
);
259 XFREE(MTYPE_PCEP
, data
);
262 /* Callback passed to pceplib when a pcep_event is ready */
263 void pcep_lib_pceplib_event_cb(void *fpt
, pcep_event
*event
)
265 pcep_thread_send_ctrl_event(fpt
, event
, pcep_thread_pcep_event
);
268 /* Wrapper function around the actual pceplib thread start function */
269 void *pcep_lib_pthread_start_passthrough(void *data
)
271 struct frr_pthread
*fpt
= data
;
272 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= fpt
->data
;
273 void *start_routine_data
= passthrough_data
->data
;
274 void *(*start_routine
)(void *) = passthrough_data
->start_routine
;
275 XFREE(MTYPE_PCEP
, passthrough_data
);
277 if (start_routine
!= NULL
) {
278 return start_routine(start_routine_data
);
284 int pcep_lib_pthread_create_cb(pthread_t
*thread_id
, const pthread_attr_t
*attr
,
285 void *(*start_routine
)(void *), void *data
,
286 const char *thread_name
)
288 /* Since FRR calls the start_routine with a struct frr_pthread,
289 * we have to store the real data and callback in a passthrough
290 * and pass the actual data the start_routine needs */
291 struct pcep_lib_pthread_passthrough_data
*passthrough_data
= XMALLOC(
292 MTYPE_PCEP
, sizeof(struct pcep_lib_pthread_passthrough_data
));
293 passthrough_data
->data
= data
;
294 passthrough_data
->start_routine
= start_routine
;
296 struct frr_pthread_attr fpt_attr
= {
297 .start
= pcep_lib_pthread_start_passthrough
,
298 .stop
= pcep_lib_pthread_stop_cb
};
299 struct frr_pthread
*fpt
=
300 frr_pthread_new(&fpt_attr
, thread_name
, "pcep_lib");
305 fpt
->data
= passthrough_data
;
306 int retval
= frr_pthread_run(fpt
, attr
);
311 *thread_id
= fpt
->thread
;
316 int pcep_lib_pthread_stop_cb(struct frr_pthread
*fpt
, void **res
)
319 frr_pthread_destroy(fpt
);
324 struct pcep_message
*pcep_lib_format_report(struct pcep_caps
*caps
,
327 double_linked_list
*objs
= pcep_lib_format_path(caps
, path
);
328 return pcep_msg_create_report(objs
);
331 static struct pcep_object_rp
*create_rp(uint32_t reqid
)
333 double_linked_list
*rp_tlvs
;
334 struct pcep_object_tlv_path_setup_type
*setup_type_tlv
;
335 struct pcep_object_rp
*rp
;
337 rp_tlvs
= dll_initialize();
338 setup_type_tlv
= pcep_tlv_create_path_setup_type(SR_TE_PST
);
339 dll_append(rp_tlvs
, setup_type_tlv
);
341 rp
= pcep_obj_create_rp(0, false, false, false, true, reqid
, rp_tlvs
);
346 struct pcep_message
*pcep_lib_format_request(struct pcep_caps
*caps
,
349 struct ipaddr
*src
= &path
->pcc_addr
;
350 struct ipaddr
*dst
= &path
->nbkey
.endpoint
;
351 double_linked_list
*objs
;
352 struct pcep_object_rp
*rp
;
353 struct pcep_object_endpoints_ipv4
*endpoints_ipv4
;
354 struct pcep_object_endpoints_ipv6
*endpoints_ipv6
;
355 struct pcep_object_objective_function
*of
= NULL
;
356 enum objfun_type objfun
= OBJFUN_UNDEFINED
;
358 assert(src
->ipa_type
== dst
->ipa_type
);
360 objs
= dll_initialize();
361 rp
= create_rp(path
->req_id
);
362 rp
->header
.flag_p
= true;
364 pcep_lib_format_constraints(path
, objs
);
366 /* Objective Function */
367 if (path
->has_pcc_objfun
) {
368 objfun
= path
->pcc_objfun
;
371 if (objfun
!= OBJFUN_UNDEFINED
) {
372 of
= pcep_obj_create_objective_function(objfun
, NULL
);
374 of
->header
.flag_p
= path
->enforce_pcc_objfun
;
375 dll_append(objs
, of
);
378 if (IS_IPADDR_V6(src
)) {
379 endpoints_ipv6
= pcep_obj_create_endpoint_ipv6(&src
->ipaddr_v6
,
381 endpoints_ipv6
->header
.flag_p
= true;
382 return pcep_msg_create_request_ipv6(rp
, endpoints_ipv6
, objs
);
384 endpoints_ipv4
= pcep_obj_create_endpoint_ipv4(&src
->ipaddr_v4
,
386 endpoints_ipv4
->header
.flag_p
= true;
387 return pcep_msg_create_request(rp
, endpoints_ipv4
, objs
);
391 struct pcep_message
*pcep_lib_format_error(int error_type
, int error_value
,
394 double_linked_list
*objs
, *srp_tlvs
;
395 struct pcep_object_srp
*srp
;
396 struct pcep_object_tlv_header
*tlv
;
398 if ((path
== NULL
) || (path
->srp_id
== 0))
399 return pcep_msg_create_error(error_type
, error_value
);
401 objs
= dll_initialize();
402 srp_tlvs
= dll_initialize();
403 tlv
= (struct pcep_object_tlv_header
*)pcep_tlv_create_path_setup_type(
405 dll_append(srp_tlvs
, tlv
);
406 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
, srp_tlvs
);
407 dll_append(objs
, srp
);
408 return pcep_msg_create_error_with_objects(error_type
, error_value
,
412 struct pcep_message
*pcep_lib_format_request_cancelled(uint32_t reqid
)
414 struct pcep_object_notify
*notify
;
415 double_linked_list
*objs
;
416 struct pcep_object_rp
*rp
;
418 notify
= pcep_obj_create_notify(
419 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED
,
420 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST
);
421 objs
= dll_initialize();
422 rp
= create_rp(reqid
);
423 dll_append(objs
, rp
);
425 return pcep_msg_create_notify(notify
, objs
);
428 struct path
*pcep_lib_parse_path(struct pcep_message
*msg
)
431 double_linked_list
*objs
= msg
->obj_list
;
432 double_linked_list_node
*node
;
434 struct pcep_object_header
*obj
;
435 struct pcep_object_rp
*rp
= NULL
;
436 struct pcep_object_srp
*srp
= NULL
;
437 struct pcep_object_lsp
*lsp
= NULL
;
438 struct pcep_object_lspa
*lspa
= NULL
;
439 struct pcep_object_ro
*ero
= NULL
;
440 struct pcep_object_metric
*metric
= NULL
;
441 struct pcep_object_bandwidth
*bandwidth
= NULL
;
442 struct pcep_object_objective_function
*of
= NULL
;
443 struct pcep_object_endpoints_ipv4
*epv4
= NULL
;
444 struct pcep_object_endpoints_ipv6
*epv6
= NULL
;
445 struct pcep_object_vendor_info
*vendor_info
= NULL
;
447 path
= pcep_new_path();
449 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
450 obj
= (struct pcep_object_header
*)node
->data
;
451 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
452 case CLASS_TYPE(PCEP_OBJ_CLASS_RP
, PCEP_OBJ_TYPE_RP
):
454 rp
= (struct pcep_object_rp
*)obj
;
455 pcep_lib_parse_rp(path
, rp
);
457 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP
, PCEP_OBJ_TYPE_SRP
):
459 srp
= (struct pcep_object_srp
*)obj
;
460 pcep_lib_parse_srp(path
, srp
);
462 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP
, PCEP_OBJ_TYPE_LSP
):
463 /* Only support single LSP per message */
465 lsp
= (struct pcep_object_lsp
*)obj
;
466 pcep_lib_parse_lsp(path
, lsp
);
468 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA
, PCEP_OBJ_TYPE_LSPA
):
469 assert(lspa
== NULL
);
470 lspa
= (struct pcep_object_lspa
*)obj
;
471 pcep_lib_parse_lspa(path
, lspa
);
473 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO
, PCEP_OBJ_TYPE_ERO
):
474 /* Only support single ERO per message */
476 ero
= (struct pcep_object_ro
*)obj
;
477 pcep_lib_parse_ero(path
, ero
);
479 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC
, PCEP_OBJ_TYPE_METRIC
):
480 metric
= (struct pcep_object_metric
*)obj
;
481 pcep_lib_parse_metric(path
, metric
);
483 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
484 PCEP_OBJ_TYPE_BANDWIDTH_REQ
):
485 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH
,
486 PCEP_OBJ_TYPE_BANDWIDTH_CISCO
):
487 bandwidth
= (struct pcep_object_bandwidth
*)obj
;
488 path
->has_bandwidth
= true;
489 path
->bandwidth
= bandwidth
->bandwidth
;
491 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH
, PCEP_OBJ_TYPE_NOPATH
):
492 path
->no_path
= true;
494 case CLASS_TYPE(PCEP_OBJ_CLASS_OF
, PCEP_OBJ_TYPE_OF
):
495 of
= (struct pcep_object_objective_function
*)obj
;
496 path
->has_pce_objfun
= true;
497 path
->pce_objfun
= of
->of_code
;
499 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
500 PCEP_OBJ_TYPE_ENDPOINT_IPV4
):
501 epv4
= (struct pcep_object_endpoints_ipv4
*)obj
;
502 pcep_lib_parse_endpoints_ipv4(path
, epv4
);
504 case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS
,
505 PCEP_OBJ_TYPE_ENDPOINT_IPV6
):
506 epv6
= (struct pcep_object_endpoints_ipv6
*)obj
;
507 pcep_lib_parse_endpoints_ipv6(path
, epv6
);
509 case CLASS_TYPE(PCEP_OBJ_CLASS_VENDOR_INFO
,
510 PCEP_OBJ_TYPE_VENDOR_INFO
):
511 vendor_info
= (struct pcep_object_vendor_info
*)obj
;
512 pcep_lib_parse_vendor_info(path
, vendor_info
);
515 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
516 "Unexpected PCEP object %s (%u) / %s (%u)",
517 pcep_object_class_name(obj
->object_class
),
519 pcep_object_type_name(obj
->object_class
,
529 void pcep_lib_parse_capabilities(struct pcep_message
*msg
,
530 struct pcep_caps
*caps
)
532 double_linked_list
*objs
= msg
->obj_list
;
533 double_linked_list_node
*node
;
535 struct pcep_object_header
*obj
;
536 struct pcep_object_open
*open
= NULL
;
538 for (node
= objs
->head
; node
!= NULL
; node
= node
->next_node
) {
539 obj
= (struct pcep_object_header
*)node
->data
;
540 switch (CLASS_TYPE(obj
->object_class
, obj
->object_type
)) {
541 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN
, PCEP_OBJ_TYPE_OPEN
):
542 assert(open
== NULL
);
543 open
= (struct pcep_object_open
*)obj
;
544 pcep_lib_parse_open(caps
, open
);
547 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT
,
548 "Unexpected PCEP object %s (%u) / %s (%u)",
549 pcep_object_class_name(obj
->object_class
),
551 pcep_object_type_name(obj
->object_class
,
559 struct counters_group
*pcep_lib_copy_counters(pcep_session
*sess
)
561 if (!sess
|| !sess
->pcep_session_counters
) {
565 return copy_counter_group(sess
->pcep_session_counters
);
568 void pcep_lib_free_counters(struct counters_group
*counters
)
570 free_counter_group(counters
);
573 pcep_session
*pcep_lib_copy_pcep_session(pcep_session
*sess
)
580 copy
= XCALLOC(MTYPE_PCEP
, sizeof(*copy
));
581 memcpy(copy
, sess
, sizeof(*copy
));
582 /* These fields should not be accessed */
583 copy
->num_unknown_messages_time_queue
= NULL
;
584 copy
->socket_comm_session
= NULL
;
585 copy
->pcep_session_counters
= NULL
;
590 /* ------------ pceplib logging callback ------------ */
592 int pceplib_logging_cb(int priority
, const char *fmt
, va_list args
)
595 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
596 PCEP_DEBUG_PCEPLIB(priority
, "pceplib: %s", buffer
);
600 /* ------------ Internal Functions ------------ */
602 double_linked_list
*pcep_lib_format_path(struct pcep_caps
*caps
,
605 struct in_addr addr_null
;
606 double_linked_list
*objs
, *srp_tlvs
, *lsp_tlvs
, *ero_objs
;
607 struct pcep_object_tlv_header
*tlv
;
608 struct pcep_object_ro_subobj
*ero_obj
;
609 struct pcep_object_srp
*srp
;
610 struct pcep_object_lsp
*lsp
;
611 struct pcep_object_ro
*ero
;
612 uint32_t encoded_binding_sid
;
613 char binding_sid_lsp_tlv_data
[6];
615 memset(&addr_null
, 0, sizeof(addr_null
));
617 objs
= dll_initialize();
619 if (path
->plsp_id
!= 0) {
621 srp_tlvs
= dll_initialize();
622 tlv
= (struct pcep_object_tlv_header
*)
623 pcep_tlv_create_path_setup_type(SR_TE_PST
);
625 dll_append(srp_tlvs
, tlv
);
626 srp
= pcep_obj_create_srp(path
->do_remove
, path
->srp_id
,
629 srp
->header
.flag_p
= true;
630 dll_append(objs
, srp
);
634 lsp_tlvs
= dll_initialize();
636 if (path
->plsp_id
== 0 || IS_IPADDR_NONE(&path
->nbkey
.endpoint
)
637 || IS_IPADDR_NONE(&path
->pcc_addr
)) {
638 tlv
= (struct pcep_object_tlv_header
*)
639 pcep_tlv_create_ipv4_lsp_identifiers(
640 &addr_null
, &addr_null
, 0, 0, &addr_null
);
642 assert(path
->pcc_addr
.ipa_type
643 == path
->nbkey
.endpoint
.ipa_type
);
644 if (IS_IPADDR_V4(&path
->pcc_addr
)) {
645 tlv
= (struct pcep_object_tlv_header
*)
646 pcep_tlv_create_ipv4_lsp_identifiers(
647 &path
->pcc_addr
.ipaddr_v4
,
648 &path
->nbkey
.endpoint
.ipaddr_v4
, 0, 0,
649 &path
->pcc_addr
.ipaddr_v4
);
651 tlv
= (struct pcep_object_tlv_header
*)
652 pcep_tlv_create_ipv6_lsp_identifiers(
653 &path
->pcc_addr
.ipaddr_v6
,
654 &path
->nbkey
.endpoint
.ipaddr_v6
, 0, 0,
655 &path
->pcc_addr
.ipaddr_v6
);
659 dll_append(lsp_tlvs
, tlv
);
660 if (path
->name
!= NULL
) {
661 tlv
= (struct pcep_object_tlv_header
*)
662 /*FIXME: Remove the typecasty when pceplib is changed
663 to take a const char* */
664 pcep_tlv_create_symbolic_path_name((char *)path
->name
,
667 dll_append(lsp_tlvs
, tlv
);
669 if ((path
->plsp_id
!= 0) && (path
->binding_sid
!= MPLS_LABEL_NONE
)) {
670 memset(binding_sid_lsp_tlv_data
, 0, 2);
671 encoded_binding_sid
= htonl(path
->binding_sid
<< 12);
672 memcpy(binding_sid_lsp_tlv_data
+ 2, &encoded_binding_sid
, 4);
673 tlv
= (struct pcep_object_tlv_header
*)
674 pcep_tlv_create_tlv_arbitrary(
675 binding_sid_lsp_tlv_data
,
676 sizeof(binding_sid_lsp_tlv_data
),
677 PCEP_OBJ_TYPE_CISCO_BSID
);
679 dll_append(lsp_tlvs
, tlv
);
681 lsp
= pcep_obj_create_lsp(
682 path
->plsp_id
, path
->status
, path
->was_created
/* C Flag */,
683 path
->go_active
/* A Flag */, path
->was_removed
/* R Flag */,
684 path
->is_synching
/* S Flag */, path
->is_delegated
/* D Flag */,
687 lsp
->header
.flag_p
= true;
688 dll_append(objs
, lsp
);
690 ero_objs
= dll_initialize();
691 for (struct path_hop
*hop
= path
->first_hop
; hop
!= NULL
;
695 /* Only supporting MPLS hops with both sid and nai */
696 assert(hop
->is_mpls
);
697 assert(hop
->has_sid
);
699 if (hop
->has_attribs
) {
700 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
,
701 hop
->sid
.mpls
.traffic_class
,
702 hop
->sid
.mpls
.is_bottom
,
705 sid
= ENCODE_SR_ERO_SID(hop
->sid
.mpls
.label
, 0, 0, 0);
710 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_ABSENT
);
712 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY
);
713 assert(hop
->nai
.type
!= PCEP_SR_SUBOBJ_NAI_UNKNOWN
);
714 switch (hop
->nai
.type
) {
715 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
716 ero_obj
= (struct pcep_object_ro_subobj
*)
717 pcep_obj_create_ro_subobj_sr_ipv4_node(
718 hop
->is_loose
, !hop
->has_sid
,
719 hop
->has_attribs
, /* C Flag */
720 hop
->is_mpls
, /* M Flag */
722 &hop
->nai
.local_addr
.ipaddr_v4
);
724 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
725 ero_obj
= (struct pcep_object_ro_subobj
*)
726 pcep_obj_create_ro_subobj_sr_ipv6_node(
727 hop
->is_loose
, !hop
->has_sid
,
728 hop
->has_attribs
, /* C Flag */
729 hop
->is_mpls
, /* M Flag */
731 &hop
->nai
.local_addr
.ipaddr_v6
);
733 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
734 ero_obj
= (struct pcep_object_ro_subobj
*)
735 pcep_obj_create_ro_subobj_sr_ipv4_adj(
736 hop
->is_loose
, !hop
->has_sid
,
737 hop
->has_attribs
, /* C Flag */
738 hop
->is_mpls
, /* M Flag */
740 &hop
->nai
.local_addr
.ipaddr_v4
,
741 &hop
->nai
.remote_addr
744 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
745 ero_obj
= (struct pcep_object_ro_subobj
*)
746 pcep_obj_create_ro_subobj_sr_ipv6_adj(
747 hop
->is_loose
, !hop
->has_sid
,
748 hop
->has_attribs
, /* C Flag */
749 hop
->is_mpls
, /* M Flag */
751 &hop
->nai
.local_addr
.ipaddr_v6
,
752 &hop
->nai
.remote_addr
755 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
756 ero_obj
= (struct pcep_object_ro_subobj
*)
757 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
758 hop
->is_loose
, !hop
->has_sid
,
759 hop
->has_attribs
, /* C Flag */
760 hop
->is_mpls
, /* M Flag */
762 hop
->nai
.local_addr
.ipaddr_v4
764 hop
->nai
.local_iface
,
765 hop
->nai
.remote_addr
.ipaddr_v4
767 hop
->nai
.remote_iface
);
773 if (ero_obj
== NULL
) {
774 ero_obj
= (struct pcep_object_ro_subobj
*)
775 pcep_obj_create_ro_subobj_sr_nonai(
777 hop
->has_attribs
, /* C Flag */
778 hop
->is_mpls
); /* M Flag */
780 dll_append(ero_objs
, ero_obj
);
782 ero
= pcep_obj_create_ero(ero_objs
);
784 ero
->header
.flag_p
= true;
785 dll_append(objs
, ero
);
787 if (path
->plsp_id
== 0) {
791 pcep_lib_format_constraints(path
, objs
);
796 void pcep_lib_format_constraints(struct path
*path
, double_linked_list
*objs
)
798 struct pcep_object_metric
*metric
;
799 struct pcep_object_bandwidth
*bandwidth
;
800 struct pcep_object_lspa
*lspa
;
803 if (path
->has_affinity_filters
) {
804 lspa
= pcep_obj_create_lspa(
805 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1],
806 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1],
807 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1],
808 DEFAULT_LSAP_SETUP_PRIO
, DEFAULT_LSAP_HOLDING_PRIO
,
809 DEFAULT_LSAP_LOCAL_PRETECTION
);
810 assert(lspa
!= NULL
);
811 lspa
->header
.flag_p
= true;
812 dll_append(objs
, lspa
);
815 /* Bandwidth Objects */
816 if (path
->has_bandwidth
) {
817 /* Requested Bandwidth */
818 bandwidth
= pcep_obj_create_bandwidth(path
->bandwidth
);
819 assert(bandwidth
!= NULL
);
820 bandwidth
->header
.flag_p
= path
->enforce_bandwidth
;
821 dll_append(objs
, bandwidth
);
825 for (struct path_metric
*m
= path
->first_metric
; m
!= NULL
;
827 metric
= pcep_obj_create_metric(m
->type
, m
->is_bound
,
828 m
->is_computed
, m
->value
);
829 assert(metric
!= NULL
);
830 metric
->header
.flag_p
= m
->enforce
;
831 dll_append(objs
, metric
);
835 void pcep_lib_parse_open(struct pcep_caps
*caps
, struct pcep_object_open
*open
)
837 double_linked_list
*tlvs
= open
->header
.tlv_list
;
838 double_linked_list_node
*node
;
839 struct pcep_object_tlv_header
*tlv_header
;
841 caps
->is_stateful
= false;
842 caps
->supported_ofs_are_known
= false;
843 caps
->supported_ofs
= 0;
845 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
846 tlv_header
= (struct pcep_object_tlv_header
*)node
->data
;
847 switch (tlv_header
->type
) {
848 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
849 pcep_lib_parse_open_pce_capability(caps
, tlv_header
);
851 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
853 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
854 pcep_lib_parse_open_objfun_list(caps
, tlv_header
);
857 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
858 "Unexpected OPEN's TLV %s (%u)",
859 pcep_tlv_type_name(tlv_header
->type
),
866 void pcep_lib_parse_open_pce_capability(
867 struct pcep_caps
*caps
, struct pcep_object_tlv_header
*tlv_header
)
869 struct pcep_object_tlv_stateful_pce_capability
*tlv
;
870 tlv
= (struct pcep_object_tlv_stateful_pce_capability
*)tlv_header
;
871 caps
->is_stateful
= tlv
->flag_u_lsp_update_capability
;
874 void pcep_lib_parse_open_objfun_list(struct pcep_caps
*caps
,
875 struct pcep_object_tlv_header
*tlv_header
)
877 double_linked_list_node
*node
;
878 struct pcep_object_tlv_of_list
*tlv
;
879 tlv
= (struct pcep_object_tlv_of_list
*)tlv_header
;
881 caps
->supported_ofs_are_known
= true;
882 for (node
= tlv
->of_list
->head
; node
!= NULL
; node
= node
->next_node
) {
883 of_code
= *(uint16_t *)node
->data
;
886 "Ignoring unexpected objective function with code %u",
890 SET_FLAG(caps
->supported_ofs
, of_code
);
894 void pcep_lib_parse_rp(struct path
*path
, struct pcep_object_rp
*rp
)
896 double_linked_list
*tlvs
= rp
->header
.tlv_list
;
897 double_linked_list_node
*node
;
898 struct pcep_object_tlv_header
*tlv
;
901 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
902 "Unexpected Empty RP's TLV plsp-id:(%d)",
903 path
? (int32_t)path
->plsp_id
: -1);
906 /* We ignore the other flags and priority for now */
907 path
->req_id
= rp
->request_id
;
908 path
->has_pce_objfun
= false;
909 path
->pce_objfun
= OBJFUN_UNDEFINED
;
911 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
912 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
914 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
915 // TODO: enforce the path setup type is SR_TE_PST
918 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
919 "Unexpected RP's TLV %s (%u)",
920 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
926 void pcep_lib_parse_srp(struct path
*path
, struct pcep_object_srp
*srp
)
928 double_linked_list
*tlvs
= srp
->header
.tlv_list
;
929 double_linked_list_node
*node
;
930 struct pcep_object_tlv_header
*tlv
;
932 path
->do_remove
= srp
->flag_lsp_remove
;
933 path
->srp_id
= srp
->srp_id_number
;
936 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
937 "Unexpected Empty SRP's TLV plsp-id:(%d)",
938 path
? (int32_t)path
->plsp_id
: -1);
941 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
942 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
944 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
945 // TODO: enforce the path setup type is SR_TE_PST
948 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
949 "Unexpected SRP's TLV %s (%u)",
950 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
956 void pcep_lib_parse_lsp(struct path
*path
, struct pcep_object_lsp
*lsp
)
958 double_linked_list
*tlvs
= lsp
->header
.tlv_list
;
959 double_linked_list_node
*node
;
960 struct pcep_object_tlv_header
*tlv
;
961 struct pcep_object_tlv_symbolic_path_name
*name
;
962 struct pcep_object_tlv_arbitrary
*arb_tlv
;
964 path
->plsp_id
= lsp
->plsp_id
;
965 path
->status
= lsp
->operational_status
;
966 path
->go_active
= lsp
->flag_a
;
967 path
->was_created
= lsp
->flag_c
;
968 path
->was_removed
= lsp
->flag_r
;
969 path
->is_synching
= lsp
->flag_s
;
970 path
->is_delegated
= lsp
->flag_d
;
973 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
974 "Unexpected Empty LSP's TLV plsp-id:(%d)",
975 path
? (int32_t)path
->plsp_id
: -1);
979 for (node
= tlvs
->head
; node
!= NULL
; node
= node
->next_node
) {
980 tlv
= (struct pcep_object_tlv_header
*)node
->data
;
982 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
983 name
= (struct pcep_object_tlv_symbolic_path_name
*)tlv
;
984 pcep_lib_parse_lsp_symbolic_name(path
, name
);
986 case PCEP_OBJ_TYPE_CISCO_BSID
:
987 arb_tlv
= (struct pcep_object_tlv_arbitrary
*)tlv
;
988 memcpy(&path
->binding_sid
, arb_tlv
->data
+ 2,
989 sizeof(path
->binding_sid
));
990 path
->binding_sid
= ntohl(path
->binding_sid
);
991 path
->binding_sid
= (path
->binding_sid
>> 12);
994 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
995 "Unexpected LSP TLV %s (%u)",
996 pcep_tlv_type_name(tlv
->type
), tlv
->type
);
1002 void pcep_lib_parse_lsp_symbolic_name(
1003 struct path
*path
, struct pcep_object_tlv_symbolic_path_name
*tlv
)
1005 uint16_t size
= tlv
->symbolic_path_name_length
;
1006 assert(path
->name
== NULL
);
1007 size
= size
> MAX_PATH_NAME_SIZE
? MAX_PATH_NAME_SIZE
: size
;
1008 path
->name
= XCALLOC(MTYPE_PCEP
, size
);
1009 strlcpy((char *)path
->name
, tlv
->symbolic_path_name
, size
+ 1);
1012 void pcep_lib_parse_lspa(struct path
*path
, struct pcep_object_lspa
*lspa
)
1014 path
->has_affinity_filters
= true;
1015 path
->affinity_filters
[AFFINITY_FILTER_EXCLUDE_ANY
- 1] =
1016 lspa
->lspa_exclude_any
;
1017 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ANY
- 1] =
1018 lspa
->lspa_include_any
;
1019 path
->affinity_filters
[AFFINITY_FILTER_INCLUDE_ALL
- 1] =
1020 lspa
->lspa_include_all
;
1023 void pcep_lib_parse_metric(struct path
*path
, struct pcep_object_metric
*obj
)
1025 struct path_metric
*metric
;
1027 metric
= pcep_new_metric();
1028 metric
->type
= obj
->type
;
1029 metric
->is_bound
= obj
->flag_b
;
1030 metric
->is_computed
= obj
->flag_c
;
1031 metric
->value
= obj
->value
;
1032 metric
->next
= path
->first_metric
;
1033 path
->first_metric
= metric
;
1036 void pcep_lib_parse_endpoints_ipv4(struct path
*path
,
1037 struct pcep_object_endpoints_ipv4
*obj
)
1039 SET_IPADDR_V4(&path
->pcc_addr
);
1040 path
->pcc_addr
.ipaddr_v4
= obj
->src_ipv4
;
1041 SET_IPADDR_V4(&path
->nbkey
.endpoint
);
1042 path
->nbkey
.endpoint
.ipaddr_v4
= obj
->dst_ipv4
;
1045 void pcep_lib_parse_endpoints_ipv6(struct path
*path
,
1046 struct pcep_object_endpoints_ipv6
*obj
)
1048 SET_IPADDR_V6(&path
->pcc_addr
);
1049 path
->pcc_addr
.ipaddr_v6
= obj
->src_ipv6
;
1050 SET_IPADDR_V6(&path
->nbkey
.endpoint
);
1051 path
->nbkey
.endpoint
.ipaddr_v6
= obj
->dst_ipv6
;
1054 void pcep_lib_parse_vendor_info(struct path
*path
,
1055 struct pcep_object_vendor_info
*obj
)
1057 if (obj
->enterprise_number
== ENTERPRISE_NUMBER_CISCO
1058 && obj
->enterprise_specific_info
== ENTERPRISE_COLOR_CISCO
)
1059 path
->nbkey
.color
= obj
->enterprise_specific_info1
;
1061 path
->nbkey
.color
= 0;
1064 void pcep_lib_parse_ero(struct path
*path
, struct pcep_object_ro
*ero
)
1066 struct path_hop
*hop
= NULL
;
1067 double_linked_list
*objs
= ero
->sub_objects
;
1068 double_linked_list_node
*node
;
1069 struct pcep_object_ro_subobj
*obj
;
1072 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV
,
1073 "Unexpected Empty ERO's sub_obj plsp-id:(%d)",
1074 path
? (int32_t)path
->plsp_id
: -1);
1077 for (node
= objs
->tail
; node
!= NULL
; node
= node
->prev_node
) {
1078 obj
= (struct pcep_object_ro_subobj
*)node
->data
;
1079 switch (obj
->ro_subobj_type
) {
1080 case RO_SUBOBJ_TYPE_SR
:
1081 hop
= pcep_lib_parse_ero_sr(
1082 hop
, (struct pcep_ro_subobj_sr
*)obj
);
1085 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ
,
1086 "Unexpected ERO sub-object %s (%u)",
1087 pcep_ro_type_name(obj
->ro_subobj_type
),
1088 obj
->ro_subobj_type
);
1093 path
->first_hop
= hop
;
1096 struct path_hop
*pcep_lib_parse_ero_sr(struct path_hop
*next
,
1097 struct pcep_ro_subobj_sr
*sr
)
1099 struct path_hop
*hop
= NULL
;
1102 /* Only support IPv4 node with SID */
1103 assert(!sr
->flag_s
);
1106 sid
.mpls
= (struct sid_mpls
){
1107 .label
= GET_SR_ERO_SID_LABEL(sr
->sid
),
1108 .traffic_class
= GET_SR_ERO_SID_TC(sr
->sid
),
1109 .is_bottom
= GET_SR_ERO_SID_S(sr
->sid
),
1110 .ttl
= GET_SR_ERO_SID_TTL(sr
->sid
)};
1112 sid
.value
= sr
->sid
;
1115 hop
= pcep_new_hop();
1116 *hop
= (struct path_hop
){.next
= next
,
1118 sr
->ro_subobj
.flag_subobj_loose_hop
,
1119 .has_sid
= !sr
->flag_s
,
1120 .is_mpls
= sr
->flag_m
,
1121 .has_attribs
= sr
->flag_c
,
1123 .has_nai
= !sr
->flag_f
,
1124 .nai
= {.type
= sr
->nai_type
}};
1127 assert(sr
->nai_list
!= NULL
);
1128 double_linked_list_node
*n
= sr
->nai_list
->head
;
1130 assert(n
->data
!= NULL
);
1131 switch (sr
->nai_type
) {
1132 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE
:
1133 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1134 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1135 sizeof(struct in_addr
));
1137 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE
:
1138 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1139 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1140 sizeof(struct in6_addr
));
1142 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY
:
1143 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1144 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1145 sizeof(struct in_addr
));
1148 assert(n
->data
!= NULL
);
1149 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1150 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1151 sizeof(struct in_addr
));
1153 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY
:
1154 hop
->nai
.local_addr
.ipa_type
= IPADDR_V6
;
1155 memcpy(&hop
->nai
.local_addr
.ipaddr_v6
, n
->data
,
1156 sizeof(struct in6_addr
));
1159 assert(n
->data
!= NULL
);
1160 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V6
;
1161 memcpy(&hop
->nai
.remote_addr
.ipaddr_v6
, n
->data
,
1162 sizeof(struct in6_addr
));
1164 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY
:
1165 hop
->nai
.local_addr
.ipa_type
= IPADDR_V4
;
1166 memcpy(&hop
->nai
.local_addr
.ipaddr_v4
, n
->data
,
1167 sizeof(struct in_addr
));
1170 assert(n
->data
!= NULL
);
1171 hop
->nai
.local_iface
= *(uint32_t *)n
->data
;
1174 assert(n
->data
!= NULL
);
1175 hop
->nai
.remote_addr
.ipa_type
= IPADDR_V4
;
1176 memcpy(&hop
->nai
.remote_addr
.ipaddr_v4
, n
->data
,
1177 sizeof(struct in_addr
));
1180 assert(n
->data
!= NULL
);
1181 hop
->nai
.remote_iface
= *(uint32_t *)n
->data
;
1184 hop
->has_nai
= false;
1185 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI
,
1186 "Unexpected SR segment NAI type %s (%u)",
1187 pcep_nai_type_name(sr
->nai_type
),
1196 struct counters_group
*copy_counter_group(struct counters_group
*from
)
1199 struct counters_group
*result
;
1202 assert(from
->max_subgroups
>= from
->num_subgroups
);
1203 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1204 memcpy(result
, from
, sizeof(*result
));
1205 size
= sizeof(struct counters_subgroup
*) * (from
->max_subgroups
+ 1);
1206 result
->subgroups
= XCALLOC(MTYPE_PCEP
, size
);
1207 for (i
= 0; i
<= from
->max_subgroups
; i
++)
1208 result
->subgroups
[i
] =
1209 copy_counter_subgroup(from
->subgroups
[i
]);
1213 struct counters_subgroup
*copy_counter_subgroup(struct counters_subgroup
*from
)
1216 struct counters_subgroup
*result
;
1219 assert(from
->max_counters
>= from
->num_counters
);
1220 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1221 memcpy(result
, from
, sizeof(*result
));
1222 size
= sizeof(struct counter
*) * (from
->max_counters
+ 1);
1223 result
->counters
= XCALLOC(MTYPE_PCEP
, size
);
1224 for (i
= 0; i
<= from
->max_counters
; i
++)
1225 result
->counters
[i
] = copy_counter(from
->counters
[i
]);
1229 struct counter
*copy_counter(struct counter
*from
)
1231 struct counter
*result
;
1234 result
= XCALLOC(MTYPE_PCEP
, sizeof(*result
));
1235 memcpy(result
, from
, sizeof(*result
));
1239 void free_counter_group(struct counters_group
*group
)
1244 for (i
= 0; i
<= group
->max_subgroups
; i
++)
1245 free_counter_subgroup(group
->subgroups
[i
]);
1246 XFREE(MTYPE_PCEP
, group
->subgroups
);
1247 XFREE(MTYPE_PCEP
, group
);
1250 void free_counter_subgroup(struct counters_subgroup
*subgroup
)
1253 if (subgroup
== NULL
)
1255 for (i
= 0; i
<= subgroup
->max_counters
; i
++)
1256 free_counter(subgroup
->counters
[i
]);
1257 XFREE(MTYPE_PCEP
, subgroup
->counters
);
1258 XFREE(MTYPE_PCEP
, subgroup
);
1261 void free_counter(struct counter
*counter
)
1263 if (counter
== NULL
)
1265 XFREE(MTYPE_PCEP
, counter
);