1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * This file is part of the PCEPlib, a PCEP protocol library.
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
7 * Author : Brady Johnson <brady@voltanet.io>
21 #include "pcep_msg_tools.h"
22 #include "pcep_msg_encoding.h"
23 #include "pcep_utils_logging.h"
24 #include "pcep_utils_memory.h"
26 static const char *message_type_strs
[] = {"NOT_IMPLEMENTED0",
39 "UNKOWN_MESSAGE_TYPE"};
41 static const char *object_class_strs
[] = {"NOT_IMPLEMENTED0",
81 "ASSOCIATION", /* 40 */
82 "UNKNOWN_MESSAGE_TYPE"};
85 double_linked_list
*pcep_msg_read(int sock_fd
)
88 uint8_t buffer
[PCEP_MESSAGE_LENGTH
] = {0};
89 uint16_t buffer_read
= 0;
92 ret
= read(sock_fd
, &buffer
, PCEP_MESSAGE_LENGTH
);
97 "%s: pcep_msg_read: Failed to read from socket fd [%d] errno [%d %s]",
98 __func__
, sock_fd
, errno
, strerror(errno
));
100 } else if (ret
== 0) {
101 pcep_log(LOG_INFO
, "%s: pcep_msg_read: Remote shutdown fd [%d]",
106 double_linked_list
*msg_list
= dll_initialize();
107 struct pcep_message
*msg
= NULL
;
109 while (((uint16_t)ret
- buffer_read
) >= MESSAGE_HEADER_LENGTH
) {
111 /* Get the Message header, validate it, and return the msg
114 pcep_decode_validate_msg_header(buffer
+ buffer_read
);
115 if (msg_length
< 0 || msg_length
> PCEP_MESSAGE_LENGTH
) {
116 /* If the message header is invalid, we cant keep
117 * reading since the length may be invalid */
120 "%s: pcep_msg_read: Received an invalid message fd [%d]",
125 /* Check if the msg_length is longer than what was read,
126 * in which case, we need to read the rest of the message. */
127 if ((ret
- buffer_read
) < msg_length
) {
128 int read_len
= (msg_length
- (ret
- buffer_read
));
132 "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]",
133 __func__
, read_len
, sock_fd
);
135 if (PCEP_MESSAGE_LENGTH
- ret
- buffer_read
>= read_len
)
137 read(sock_fd
, &buffer
[ret
], read_len
);
141 "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)",
142 __func__
, read_len
, ret
,
143 PCEP_MESSAGE_LENGTH
);
147 if (read_ret
!= read_len
) {
150 "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]",
151 __func__
, read_ret
, read_len
, sock_fd
);
156 msg
= pcep_decode_message(buffer
+ buffer_read
);
157 buffer_read
+= msg_length
;
162 dll_append(msg_list
, msg
);
169 struct pcep_message
*pcep_msg_get(double_linked_list
*msg_list
, uint8_t type
)
171 if (msg_list
== NULL
) {
175 double_linked_list_node
*node
;
176 for (node
= msg_list
->head
; node
!= NULL
; node
= node
->next_node
) {
177 if (((struct pcep_message
*)node
->data
)->msg_header
->type
179 return (struct pcep_message
*)node
->data
;
186 struct pcep_message
*pcep_msg_get_next(double_linked_list
*list
,
187 struct pcep_message
*current
,
190 if (list
== NULL
|| current
== NULL
) {
194 if (list
->head
== NULL
) {
198 double_linked_list_node
*node
;
199 for (node
= list
->head
; node
!= NULL
; node
= node
->next_node
) {
200 if (node
->data
== current
) {
204 if (((struct pcep_message
*)node
->data
)->msg_header
->type
206 return (struct pcep_message
*)node
->data
;
213 struct pcep_object_header
*pcep_obj_get(double_linked_list
*list
,
214 uint8_t object_class
)
220 if (list
->head
== NULL
) {
224 double_linked_list_node
*obj_item
;
225 for (obj_item
= list
->head
; obj_item
!= NULL
;
226 obj_item
= obj_item
->next_node
) {
227 if (((struct pcep_object_header
*)obj_item
->data
)->object_class
229 return (struct pcep_object_header
*)obj_item
->data
;
236 struct pcep_object_header
*pcep_obj_get_next(double_linked_list
*list
,
237 struct pcep_object_header
*current
,
238 uint8_t object_class
)
240 if (list
== NULL
|| current
== NULL
) {
244 if (list
->head
== NULL
) {
248 double_linked_list_node
*node
;
249 for (node
= list
->head
; node
!= NULL
; node
= node
->next_node
) {
250 if (node
->data
== current
) {
254 if (((struct pcep_object_header
*)node
->data
)->object_class
256 return (struct pcep_object_header
*)node
->data
;
263 void pcep_obj_free_tlv(struct pcep_object_tlv_header
*tlv
)
265 /* Specific TLV freeing */
267 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
268 if (((struct pcep_object_tlv_speaker_entity_identifier
*)tlv
)
269 ->speaker_entity_id_list
271 dll_destroy_with_data_memtype(
273 pcep_object_tlv_speaker_entity_identifier
*)
275 ->speaker_entity_id_list
,
280 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
281 if (((struct pcep_object_tlv_path_setup_type_capability
*)tlv
)
284 dll_destroy_with_data_memtype(
286 pcep_object_tlv_path_setup_type_capability
*)
292 if (((struct pcep_object_tlv_path_setup_type_capability
*)tlv
)
295 dll_destroy_with_data_memtype(
297 pcep_object_tlv_path_setup_type_capability
*)
304 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
305 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
306 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
307 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
308 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
309 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
310 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
311 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
312 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
313 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
314 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
315 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
316 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
317 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
318 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
319 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
320 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
321 case PCEP_OBJ_TYPE_CISCO_BSID
:
322 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
326 pceplib_free(PCEPLIB_MESSAGES
, tlv
);
329 void pcep_obj_free_object(struct pcep_object_header
*obj
)
331 /* Iterate the TLVs and free each one */
332 if (obj
->tlv_list
!= NULL
) {
333 struct pcep_object_tlv_header
*tlv
;
334 while ((tlv
= (struct pcep_object_tlv_header
*)
335 dll_delete_first_node(obj
->tlv_list
))
337 pcep_obj_free_tlv(tlv
);
340 dll_destroy(obj
->tlv_list
);
343 /* Specific object freeing */
344 switch (obj
->object_class
) {
345 case PCEP_OBJ_CLASS_ERO
:
346 case PCEP_OBJ_CLASS_IRO
:
347 case PCEP_OBJ_CLASS_RRO
: {
348 if (((struct pcep_object_ro
*)obj
)->sub_objects
!= NULL
) {
349 double_linked_list_node
*node
=
350 ((struct pcep_object_ro
*)obj
)
352 for (; node
!= NULL
; node
= node
->next_node
) {
353 struct pcep_object_ro_subobj
*ro_subobj
=
354 (struct pcep_object_ro_subobj
*)
356 if (ro_subobj
->ro_subobj_type
357 == RO_SUBOBJ_TYPE_SR
) {
358 if (((struct pcep_ro_subobj_sr
*)
362 dll_destroy_with_data_memtype(
371 dll_destroy_with_data_memtype(
372 ((struct pcep_object_ro
*)obj
)->sub_objects
,
377 case PCEP_OBJ_CLASS_SVEC
:
378 if (((struct pcep_object_svec
*)obj
)->request_id_list
!= NULL
) {
379 dll_destroy_with_data_memtype(
380 ((struct pcep_object_svec
*)obj
)
386 case PCEP_OBJ_CLASS_SWITCH_LAYER
:
387 if (((struct pcep_object_switch_layer
*)obj
)->switch_layer_rows
389 dll_destroy_with_data_memtype(
390 ((struct pcep_object_switch_layer
*)obj
)
396 case PCEP_OBJ_CLASS_OPEN
:
397 case PCEP_OBJ_CLASS_RP
:
398 case PCEP_OBJ_CLASS_NOPATH
:
399 case PCEP_OBJ_CLASS_ENDPOINTS
:
400 case PCEP_OBJ_CLASS_BANDWIDTH
:
401 case PCEP_OBJ_CLASS_METRIC
:
402 case PCEP_OBJ_CLASS_LSPA
:
403 case PCEP_OBJ_CLASS_NOTF
:
404 case PCEP_OBJ_CLASS_ERROR
:
405 case PCEP_OBJ_CLASS_CLOSE
:
406 case PCEP_OBJ_CLASS_OF
:
407 case PCEP_OBJ_CLASS_LSP
:
408 case PCEP_OBJ_CLASS_SRP
:
409 case PCEP_OBJ_CLASS_VENDOR_INFO
:
410 case PCEP_OBJ_CLASS_INTER_LAYER
:
411 case PCEP_OBJ_CLASS_REQ_ADAP_CAP
:
412 case PCEP_OBJ_CLASS_SERVER_IND
:
413 case PCEP_OBJ_CLASS_ASSOCIATION
:
414 case PCEP_OBJ_CLASS_MAX
:
418 pceplib_free(PCEPLIB_MESSAGES
, obj
);
421 void pcep_msg_free_message(struct pcep_message
*message
)
423 /* Iterate the objects and free each one */
424 if (message
->obj_list
!= NULL
) {
425 struct pcep_object_header
*obj
;
426 while ((obj
= (struct pcep_object_header
*)
427 dll_delete_first_node(message
->obj_list
))
429 pcep_obj_free_object(obj
);
432 dll_destroy(message
->obj_list
);
435 if (message
->msg_header
!= NULL
) {
436 pceplib_free(PCEPLIB_MESSAGES
, message
->msg_header
);
439 if (message
->encoded_message
!= NULL
) {
440 pceplib_free(PCEPLIB_MESSAGES
, message
->encoded_message
);
443 pceplib_free(PCEPLIB_MESSAGES
, message
);
446 void pcep_msg_free_message_list(double_linked_list
*list
)
448 /* Iterate the messages and free each one */
449 struct pcep_message
*msg
;
450 while ((msg
= (struct pcep_message
*)dll_delete_first_node(list
))
452 pcep_msg_free_message(msg
);
458 const char *get_message_type_str(uint8_t type
)
461 (type
> PCEP_TYPE_INITIATE
) ? PCEP_TYPE_INITIATE
+ 1 : type
;
463 return message_type_strs
[msg_type
];
466 const char *get_object_class_str(uint8_t class)
468 uint8_t object_class
=
469 (class > PCEP_OBJ_CLASS_SRP
) ? PCEP_OBJ_CLASS_SRP
+ 1 : class;
471 return object_class_strs
[object_class
];
474 /* Expecting a list of struct pcep_message pointers */
475 void pcep_msg_print(double_linked_list
*msg_list
)
477 double_linked_list_node
*node
;
478 for (node
= msg_list
->head
; node
!= NULL
; node
= node
->next_node
) {
479 struct pcep_message
*msg
= (struct pcep_message
*)node
->data
;
480 pcep_log(LOG_INFO
, "%s: PCEP_MSG %s", __func__
,
481 get_message_type_str(msg
->msg_header
->type
));
483 double_linked_list_node
*obj_node
=
484 (msg
->obj_list
== NULL
? NULL
: msg
->obj_list
->head
);
485 for (; obj_node
!= NULL
; obj_node
= obj_node
->next_node
) {
486 struct pcep_object_header
*obj_header
=
487 ((struct pcep_object_header
*)obj_node
->data
);
489 LOG_INFO
, "%s: PCEP_OBJ %s", __func__
,
490 get_object_class_str(obj_header
->object_class
));
495 int pcep_msg_send(int sock_fd
, struct pcep_message
*msg
)
500 int msg_length
= ntohs(msg
->encoded_message_length
);
501 if (msg_length
> PCEP_MESSAGE_LENGTH
) {
502 pcep_log(LOG_ERR
, "%s: Not sended, size(% d) exceed max(% d) ",
503 __func__
, msg_length
, PCEP_MESSAGE_LENGTH
);
507 return write(sock_fd
, msg
->encoded_message
, msg_length
);