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