]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_msg_tools.c
Merge pull request #12654 from Pdoijode/evpn-evi-detail-json-changes
[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
fdfa6ecf
DS
316 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR:
317 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST:
318 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO:
319 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
320 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME:
321 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS:
322 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS:
323 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE:
324 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC:
325 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION:
326 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
327 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
328 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID:
329 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME:
330 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID:
331 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE:
332 case PCEP_OBJ_TLV_TYPE_UNKNOWN:
333 case PCEP_OBJ_TYPE_CISCO_BSID:
334 case PCEP_OBJ_TLV_TYPE_ARBITRARY:
74971473
JG
335 break;
336 }
337
338 pceplib_free(PCEPLIB_MESSAGES, tlv);
339}
340
341void pcep_obj_free_object(struct pcep_object_header *obj)
342{
343 /* Iterate the TLVs and free each one */
344 if (obj->tlv_list != NULL) {
345 struct pcep_object_tlv_header *tlv;
346 while ((tlv = (struct pcep_object_tlv_header *)
347 dll_delete_first_node(obj->tlv_list))
348 != NULL) {
349 pcep_obj_free_tlv(tlv);
350 }
351
352 dll_destroy(obj->tlv_list);
353 }
354
355 /* Specific object freeing */
356 switch (obj->object_class) {
357 case PCEP_OBJ_CLASS_ERO:
358 case PCEP_OBJ_CLASS_IRO:
359 case PCEP_OBJ_CLASS_RRO: {
360 if (((struct pcep_object_ro *)obj)->sub_objects != NULL) {
361 double_linked_list_node *node =
362 ((struct pcep_object_ro *)obj)
363 ->sub_objects->head;
364 for (; node != NULL; node = node->next_node) {
365 struct pcep_object_ro_subobj *ro_subobj =
366 (struct pcep_object_ro_subobj *)
367 node->data;
368 if (ro_subobj->ro_subobj_type
369 == RO_SUBOBJ_TYPE_SR) {
370 if (((struct pcep_ro_subobj_sr *)
371 ro_subobj)
372 ->nai_list
373 != NULL) {
374 dll_destroy_with_data_memtype(
375 ((struct
376 pcep_ro_subobj_sr *)
377 ro_subobj)
378 ->nai_list,
379 PCEPLIB_MESSAGES);
380 }
381 }
382 }
383 dll_destroy_with_data_memtype(
384 ((struct pcep_object_ro *)obj)->sub_objects,
385 PCEPLIB_MESSAGES);
386 }
387 } break;
388
389 case PCEP_OBJ_CLASS_SVEC:
390 if (((struct pcep_object_svec *)obj)->request_id_list != NULL) {
391 dll_destroy_with_data_memtype(
392 ((struct pcep_object_svec *)obj)
393 ->request_id_list,
394 PCEPLIB_MESSAGES);
395 }
396 break;
397
398 case PCEP_OBJ_CLASS_SWITCH_LAYER:
399 if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows
400 != NULL) {
401 dll_destroy_with_data_memtype(
402 ((struct pcep_object_switch_layer *)obj)
403 ->switch_layer_rows,
404 PCEPLIB_MESSAGES);
405 }
406 break;
407
fdfa6ecf
DS
408 case PCEP_OBJ_CLASS_OPEN:
409 case PCEP_OBJ_CLASS_RP:
410 case PCEP_OBJ_CLASS_NOPATH:
411 case PCEP_OBJ_CLASS_ENDPOINTS:
412 case PCEP_OBJ_CLASS_BANDWIDTH:
413 case PCEP_OBJ_CLASS_METRIC:
414 case PCEP_OBJ_CLASS_LSPA:
415 case PCEP_OBJ_CLASS_NOTF:
416 case PCEP_OBJ_CLASS_ERROR:
417 case PCEP_OBJ_CLASS_CLOSE:
418 case PCEP_OBJ_CLASS_OF:
419 case PCEP_OBJ_CLASS_LSP:
420 case PCEP_OBJ_CLASS_SRP:
421 case PCEP_OBJ_CLASS_VENDOR_INFO:
422 case PCEP_OBJ_CLASS_INTER_LAYER:
423 case PCEP_OBJ_CLASS_REQ_ADAP_CAP:
424 case PCEP_OBJ_CLASS_SERVER_IND:
425 case PCEP_OBJ_CLASS_ASSOCIATION:
426 case PCEP_OBJ_CLASS_MAX:
74971473
JG
427 break;
428 }
429
430 pceplib_free(PCEPLIB_MESSAGES, obj);
431}
432
433void pcep_msg_free_message(struct pcep_message *message)
434{
435 /* Iterate the objects and free each one */
436 if (message->obj_list != NULL) {
437 struct pcep_object_header *obj;
438 while ((obj = (struct pcep_object_header *)
439 dll_delete_first_node(message->obj_list))
440 != NULL) {
441 pcep_obj_free_object(obj);
442 }
443
444 dll_destroy(message->obj_list);
445 }
446
447 if (message->msg_header != NULL) {
448 pceplib_free(PCEPLIB_MESSAGES, message->msg_header);
449 }
450
451 if (message->encoded_message != NULL) {
452 pceplib_free(PCEPLIB_MESSAGES, message->encoded_message);
453 }
454
455 pceplib_free(PCEPLIB_MESSAGES, message);
456}
457
458void pcep_msg_free_message_list(double_linked_list *list)
459{
460 /* Iterate the messages and free each one */
461 struct pcep_message *msg;
462 while ((msg = (struct pcep_message *)dll_delete_first_node(list))
463 != NULL) {
464 pcep_msg_free_message(msg);
465 }
466
467 dll_destroy(list);
468}
469
470const char *get_message_type_str(uint8_t type)
471{
472 uint8_t msg_type =
473 (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type;
474
475 return message_type_strs[msg_type];
476}
477
478const char *get_object_class_str(uint8_t class)
479{
480 uint8_t object_class =
481 (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class;
482
483 return object_class_strs[object_class];
484}
485
486/* Expecting a list of struct pcep_message pointers */
487void pcep_msg_print(double_linked_list *msg_list)
488{
489 double_linked_list_node *node;
490 for (node = msg_list->head; node != NULL; node = node->next_node) {
491 struct pcep_message *msg = (struct pcep_message *)node->data;
492 pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__,
493 get_message_type_str(msg->msg_header->type));
494
495 double_linked_list_node *obj_node =
496 (msg->obj_list == NULL ? NULL : msg->obj_list->head);
497 for (; obj_node != NULL; obj_node = obj_node->next_node) {
498 struct pcep_object_header *obj_header =
499 ((struct pcep_object_header *)obj_node->data);
500 pcep_log(
501 LOG_INFO, "%s: PCEP_OBJ %s", __func__,
502 get_object_class_str(obj_header->object_class));
503 }
504 }
505}
506
507int pcep_msg_send(int sock_fd, struct pcep_message *msg)
508{
509 if (msg == NULL) {
510 return 0;
511 }
7ed8c4b1
JG
512 int msg_length = ntohs(msg->encoded_message_length);
513 if (msg_length > PCEP_MESSAGE_LENGTH) {
514 pcep_log(LOG_ERR, "%s: Not sended, size(% d) exceed max(% d) ",
515 __func__, msg_length, PCEP_MESSAGE_LENGTH);
516 return 0;
517 }
74971473 518
7ed8c4b1 519 return write(sock_fd, msg->encoded_message, msg_length);
74971473 520}