]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_msg_tools.c
Merge pull request #12219 from cscarpitta/feature/srv6-usid-behavior-support
[mirror_frr.git] / pceplib / pcep_msg_tools.c
CommitLineData
74971473
JG
1/*
2 * This file is part of the PCEPlib, a PCEP protocol library.
3 *
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 *
19 * Author : Brady Johnson <brady@voltanet.io>
20 *
21 */
22
23
1f8031f7
DL
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
74971473
JG
28#include <errno.h>
29#include <stdio.h>
30#include <string.h>
31#include <unistd.h>
32
33#include "pcep_msg_tools.h"
34#include "pcep_msg_encoding.h"
35#include "pcep_utils_logging.h"
36#include "pcep_utils_memory.h"
37
38static const char *message_type_strs[] = {"NOT_IMPLEMENTED0",
39 "OPEN",
40 "KEEPALIVE",
41 "PCREQ",
42 "PCREP",
43 "PCNOTF",
44 "ERROR",
45 "CLOSE",
46 "NOT_IMPLEMENTED8",
47 "NOT_IMPLEMENTED9",
48 "REPORT",
49 "UPDATE",
50 "INITIATE",
51 "UNKOWN_MESSAGE_TYPE"};
52
53static const char *object_class_strs[] = {"NOT_IMPLEMENTED0",
54 "OPEN",
55 "RP",
56 "NOPATH",
57 "ENDPOINTS",
58 "BANDWIDTH",
59 "METRIC",
60 "ERO",
61 "RRO",
62 "LSPA",
63 "IRO",
64 "SVEC",
65 "NOTF",
66 "ERROR",
67 "NOT_IMPLEMENTED14",
68 "CLOSE",
69 "NOT_IMPLEMENTED16",
70 "NOT_IMPLEMENTED17",
71 "NOT_IMPLEMENTED18",
72 "NOT_IMPLEMENTED19",
73 "NOT_IMPLEMENTED20",
74 "OBJECTIVE_FUNCTION",
75 "NOT_IMPLEMENTED22",
76 "NOT_IMPLEMENTED23",
77 "NOT_IMPLEMENTED24",
78 "NOT_IMPLEMENTED25",
79 "NOT_IMPLEMENTED26",
80 "NOT_IMPLEMENTED27",
81 "NOT_IMPLEMENTED28",
82 "NOT_IMPLEMENTED29",
83 "NOT_IMPLEMENTED30",
84 "NOT_IMPLEMENTED31",
85 "LSP",
86 "SRP",
87 "VENDOR_INFO",
88 "NOT_IMPLEMENTED35",
89 "INTER_LAYER",
90 "SWITCH_LAYER",
91 "REQ_ADAP_CAP",
92 "SERVER_IND",
93 "ASSOCIATION", /* 40 */
94 "UNKNOWN_MESSAGE_TYPE"};
95
96
97double_linked_list *pcep_msg_read(int sock_fd)
98{
99 int ret;
7ed8c4b1 100 uint8_t buffer[PCEP_MESSAGE_LENGTH] = {0};
74971473
JG
101 uint16_t buffer_read = 0;
102
103
7ed8c4b1 104 ret = read(sock_fd, &buffer, PCEP_MESSAGE_LENGTH);
74971473
JG
105
106 if (ret < 0) {
107 pcep_log(
108 LOG_INFO,
109 "%s: pcep_msg_read: Failed to read from socket fd [%d] errno [%d %s]",
110 __func__, sock_fd, errno, strerror(errno));
111 return NULL;
112 } else if (ret == 0) {
113 pcep_log(LOG_INFO, "%s: pcep_msg_read: Remote shutdown fd [%d]",
114 __func__, sock_fd);
115 return NULL;
116 }
117
118 double_linked_list *msg_list = dll_initialize();
119 struct pcep_message *msg = NULL;
120
7ed8c4b1 121 while (((uint16_t)ret - buffer_read) >= MESSAGE_HEADER_LENGTH) {
74971473
JG
122
123 /* Get the Message header, validate it, and return the msg
124 * length */
7ed8c4b1 125 int32_t msg_length =
74971473 126 pcep_decode_validate_msg_header(buffer + buffer_read);
7ed8c4b1 127 if (msg_length < 0 || msg_length > PCEP_MESSAGE_LENGTH) {
74971473
JG
128 /* If the message header is invalid, we cant keep
129 * reading since the length may be invalid */
130 pcep_log(
131 LOG_INFO,
132 "%s: pcep_msg_read: Received an invalid message fd [%d]",
133 __func__, sock_fd);
134 return msg_list;
135 }
136
7ed8c4b1 137 /* Check if the msg_length is longer than what was read,
74971473 138 * in which case, we need to read the rest of the message. */
7ed8c4b1
JG
139 if ((ret - buffer_read) < msg_length) {
140 int read_len = (msg_length - (ret - buffer_read));
74971473
JG
141 int read_ret = 0;
142 pcep_log(
143 LOG_INFO,
144 "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]",
145 __func__, read_len, sock_fd);
146
b8cc7b62 147 if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len)
7ed8c4b1
JG
148 read_ret =
149 read(sock_fd, &buffer[ret], read_len);
150 else {
151 pcep_log(
152 LOG_ERR,
153 "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)",
b8cc7b62
QY
154 __func__, read_len, ret,
155 PCEP_MESSAGE_LENGTH);
7ed8c4b1
JG
156 return msg_list;
157 }
74971473
JG
158
159 if (read_ret != read_len) {
160 pcep_log(
161 LOG_INFO,
162 "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]",
163 __func__, read_ret, read_len, sock_fd);
164 return msg_list;
165 }
166 }
167
168 msg = pcep_decode_message(buffer + buffer_read);
7ed8c4b1 169 buffer_read += msg_length;
74971473
JG
170
171 if (msg == NULL) {
172 return msg_list;
173 } else {
174 dll_append(msg_list, msg);
175 }
176 }
177
178 return msg_list;
179}
180
181struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type)
182{
183 if (msg_list == NULL) {
184 return NULL;
185 }
186
187 double_linked_list_node *node;
188 for (node = msg_list->head; node != NULL; node = node->next_node) {
189 if (((struct pcep_message *)node->data)->msg_header->type
190 == type) {
191 return (struct pcep_message *)node->data;
192 }
193 }
194
195 return NULL;
196}
197
198struct pcep_message *pcep_msg_get_next(double_linked_list *list,
199 struct pcep_message *current,
200 uint8_t type)
201{
202 if (list == NULL || current == NULL) {
203 return NULL;
204 }
205
206 if (list->head == NULL) {
207 return NULL;
208 }
209
210 double_linked_list_node *node;
211 for (node = list->head; node != NULL; node = node->next_node) {
212 if (node->data == current) {
213 continue;
214 }
215
216 if (((struct pcep_message *)node->data)->msg_header->type
217 == type) {
218 return (struct pcep_message *)node->data;
219 }
220 }
221
222 return NULL;
223}
224
225struct pcep_object_header *pcep_obj_get(double_linked_list *list,
226 uint8_t object_class)
227{
228 if (list == NULL) {
229 return NULL;
230 }
231
232 if (list->head == NULL) {
233 return NULL;
234 }
235
236 double_linked_list_node *obj_item;
237 for (obj_item = list->head; obj_item != NULL;
238 obj_item = obj_item->next_node) {
239 if (((struct pcep_object_header *)obj_item->data)->object_class
240 == object_class) {
241 return (struct pcep_object_header *)obj_item->data;
242 }
243 }
244
245 return NULL;
246}
247
248struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
249 struct pcep_object_header *current,
250 uint8_t object_class)
251{
252 if (list == NULL || current == NULL) {
253 return NULL;
254 }
255
256 if (list->head == NULL) {
257 return NULL;
258 }
259
260 double_linked_list_node *node;
261 for (node = list->head; node != NULL; node = node->next_node) {
262 if (node->data == current) {
263 continue;
264 }
265
266 if (((struct pcep_object_header *)node->data)->object_class
267 == object_class) {
268 return (struct pcep_object_header *)node->data;
269 }
270 }
271
272 return NULL;
273}
274
275void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv)
276{
277 /* Specific TLV freeing */
278 switch (tlv->type) {
279 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
280 if (((struct pcep_object_tlv_speaker_entity_identifier *)tlv)
281 ->speaker_entity_id_list
282 != NULL) {
283 dll_destroy_with_data_memtype(
284 ((struct
285 pcep_object_tlv_speaker_entity_identifier *)
286 tlv)
287 ->speaker_entity_id_list,
288 PCEPLIB_MESSAGES);
289 }
290 break;
291
292 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
293 if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
294 ->pst_list
295 != NULL) {
296 dll_destroy_with_data_memtype(
297 ((struct
298 pcep_object_tlv_path_setup_type_capability *)
299 tlv)
300 ->pst_list,
301 PCEPLIB_MESSAGES);
302 }
303
304 if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
305 ->sub_tlv_list
306 != NULL) {
307 dll_destroy_with_data_memtype(
308 ((struct
309 pcep_object_tlv_path_setup_type_capability *)
310 tlv)
311 ->sub_tlv_list,
312 PCEPLIB_MESSAGES);
313 }
314 break;
315
316 default:
317 break;
318 }
319
320 pceplib_free(PCEPLIB_MESSAGES, tlv);
321}
322
323void pcep_obj_free_object(struct pcep_object_header *obj)
324{
325 /* Iterate the TLVs and free each one */
326 if (obj->tlv_list != NULL) {
327 struct pcep_object_tlv_header *tlv;
328 while ((tlv = (struct pcep_object_tlv_header *)
329 dll_delete_first_node(obj->tlv_list))
330 != NULL) {
331 pcep_obj_free_tlv(tlv);
332 }
333
334 dll_destroy(obj->tlv_list);
335 }
336
337 /* Specific object freeing */
338 switch (obj->object_class) {
339 case PCEP_OBJ_CLASS_ERO:
340 case PCEP_OBJ_CLASS_IRO:
341 case PCEP_OBJ_CLASS_RRO: {
342 if (((struct pcep_object_ro *)obj)->sub_objects != NULL) {
343 double_linked_list_node *node =
344 ((struct pcep_object_ro *)obj)
345 ->sub_objects->head;
346 for (; node != NULL; node = node->next_node) {
347 struct pcep_object_ro_subobj *ro_subobj =
348 (struct pcep_object_ro_subobj *)
349 node->data;
350 if (ro_subobj->ro_subobj_type
351 == RO_SUBOBJ_TYPE_SR) {
352 if (((struct pcep_ro_subobj_sr *)
353 ro_subobj)
354 ->nai_list
355 != NULL) {
356 dll_destroy_with_data_memtype(
357 ((struct
358 pcep_ro_subobj_sr *)
359 ro_subobj)
360 ->nai_list,
361 PCEPLIB_MESSAGES);
362 }
363 }
364 }
365 dll_destroy_with_data_memtype(
366 ((struct pcep_object_ro *)obj)->sub_objects,
367 PCEPLIB_MESSAGES);
368 }
369 } break;
370
371 case PCEP_OBJ_CLASS_SVEC:
372 if (((struct pcep_object_svec *)obj)->request_id_list != NULL) {
373 dll_destroy_with_data_memtype(
374 ((struct pcep_object_svec *)obj)
375 ->request_id_list,
376 PCEPLIB_MESSAGES);
377 }
378 break;
379
380 case PCEP_OBJ_CLASS_SWITCH_LAYER:
381 if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows
382 != NULL) {
383 dll_destroy_with_data_memtype(
384 ((struct pcep_object_switch_layer *)obj)
385 ->switch_layer_rows,
386 PCEPLIB_MESSAGES);
387 }
388 break;
389
390 default:
391 break;
392 }
393
394 pceplib_free(PCEPLIB_MESSAGES, obj);
395}
396
397void pcep_msg_free_message(struct pcep_message *message)
398{
399 /* Iterate the objects and free each one */
400 if (message->obj_list != NULL) {
401 struct pcep_object_header *obj;
402 while ((obj = (struct pcep_object_header *)
403 dll_delete_first_node(message->obj_list))
404 != NULL) {
405 pcep_obj_free_object(obj);
406 }
407
408 dll_destroy(message->obj_list);
409 }
410
411 if (message->msg_header != NULL) {
412 pceplib_free(PCEPLIB_MESSAGES, message->msg_header);
413 }
414
415 if (message->encoded_message != NULL) {
416 pceplib_free(PCEPLIB_MESSAGES, message->encoded_message);
417 }
418
419 pceplib_free(PCEPLIB_MESSAGES, message);
420}
421
422void pcep_msg_free_message_list(double_linked_list *list)
423{
424 /* Iterate the messages and free each one */
425 struct pcep_message *msg;
426 while ((msg = (struct pcep_message *)dll_delete_first_node(list))
427 != NULL) {
428 pcep_msg_free_message(msg);
429 }
430
431 dll_destroy(list);
432}
433
434const char *get_message_type_str(uint8_t type)
435{
436 uint8_t msg_type =
437 (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type;
438
439 return message_type_strs[msg_type];
440}
441
442const char *get_object_class_str(uint8_t class)
443{
444 uint8_t object_class =
445 (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class;
446
447 return object_class_strs[object_class];
448}
449
450/* Expecting a list of struct pcep_message pointers */
451void pcep_msg_print(double_linked_list *msg_list)
452{
453 double_linked_list_node *node;
454 for (node = msg_list->head; node != NULL; node = node->next_node) {
455 struct pcep_message *msg = (struct pcep_message *)node->data;
456 pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__,
457 get_message_type_str(msg->msg_header->type));
458
459 double_linked_list_node *obj_node =
460 (msg->obj_list == NULL ? NULL : msg->obj_list->head);
461 for (; obj_node != NULL; obj_node = obj_node->next_node) {
462 struct pcep_object_header *obj_header =
463 ((struct pcep_object_header *)obj_node->data);
464 pcep_log(
465 LOG_INFO, "%s: PCEP_OBJ %s", __func__,
466 get_object_class_str(obj_header->object_class));
467 }
468 }
469}
470
471int pcep_msg_send(int sock_fd, struct pcep_message *msg)
472{
473 if (msg == NULL) {
474 return 0;
475 }
7ed8c4b1
JG
476 int msg_length = ntohs(msg->encoded_message_length);
477 if (msg_length > PCEP_MESSAGE_LENGTH) {
478 pcep_log(LOG_ERR, "%s: Not sended, size(% d) exceed max(% d) ",
479 __func__, msg_length, PCEP_MESSAGE_LENGTH);
480 return 0;
481 }
74971473 482
7ed8c4b1 483 return write(sock_fd, msg->encoded_message, msg_length);
74971473 484}