]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_msg_tools.c
pceplib: Integrate pcelib into frr
[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
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
34static 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
49static 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
93double_linked_list *pcep_msg_read(int sock_fd)
94{
95 int ret;
96 uint8_t buffer[PCEP_MAX_SIZE] = {0};
97 uint16_t buffer_read = 0;
98
99
100 ret = read(sock_fd, &buffer, PCEP_MAX_SIZE);
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 ((ret - buffer_read) >= MESSAGE_HEADER_LENGTH) {
118
119 /* Get the Message header, validate it, and return the msg
120 * length */
121 int32_t msg_hdr_length =
122 pcep_decode_validate_msg_header(buffer + buffer_read);
123 if (msg_hdr_length < 0) {
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_hdr_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_hdr_length) {
136 int read_len = (msg_hdr_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 read_ret = read(sock_fd, &buffer[ret], read_len);
144
145 if (read_ret != read_len) {
146 pcep_log(
147 LOG_INFO,
148 "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]",
149 __func__, read_ret, read_len, sock_fd);
150 return msg_list;
151 }
152 }
153
154 msg = pcep_decode_message(buffer + buffer_read);
155 buffer_read += msg_hdr_length;
156
157 if (msg == NULL) {
158 return msg_list;
159 } else {
160 dll_append(msg_list, msg);
161 }
162 }
163
164 return msg_list;
165}
166
167struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type)
168{
169 if (msg_list == NULL) {
170 return NULL;
171 }
172
173 double_linked_list_node *node;
174 for (node = msg_list->head; node != NULL; node = node->next_node) {
175 if (((struct pcep_message *)node->data)->msg_header->type
176 == type) {
177 return (struct pcep_message *)node->data;
178 }
179 }
180
181 return NULL;
182}
183
184struct pcep_message *pcep_msg_get_next(double_linked_list *list,
185 struct pcep_message *current,
186 uint8_t type)
187{
188 if (list == NULL || current == NULL) {
189 return NULL;
190 }
191
192 if (list->head == NULL) {
193 return NULL;
194 }
195
196 double_linked_list_node *node;
197 for (node = list->head; node != NULL; node = node->next_node) {
198 if (node->data == current) {
199 continue;
200 }
201
202 if (((struct pcep_message *)node->data)->msg_header->type
203 == type) {
204 return (struct pcep_message *)node->data;
205 }
206 }
207
208 return NULL;
209}
210
211struct pcep_object_header *pcep_obj_get(double_linked_list *list,
212 uint8_t object_class)
213{
214 if (list == NULL) {
215 return NULL;
216 }
217
218 if (list->head == NULL) {
219 return NULL;
220 }
221
222 double_linked_list_node *obj_item;
223 for (obj_item = list->head; obj_item != NULL;
224 obj_item = obj_item->next_node) {
225 if (((struct pcep_object_header *)obj_item->data)->object_class
226 == object_class) {
227 return (struct pcep_object_header *)obj_item->data;
228 }
229 }
230
231 return NULL;
232}
233
234struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
235 struct pcep_object_header *current,
236 uint8_t object_class)
237{
238 if (list == NULL || current == NULL) {
239 return NULL;
240 }
241
242 if (list->head == NULL) {
243 return NULL;
244 }
245
246 double_linked_list_node *node;
247 for (node = list->head; node != NULL; node = node->next_node) {
248 if (node->data == current) {
249 continue;
250 }
251
252 if (((struct pcep_object_header *)node->data)->object_class
253 == object_class) {
254 return (struct pcep_object_header *)node->data;
255 }
256 }
257
258 return NULL;
259}
260
261void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv)
262{
263 /* Specific TLV freeing */
264 switch (tlv->type) {
265 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
266 if (((struct pcep_object_tlv_speaker_entity_identifier *)tlv)
267 ->speaker_entity_id_list
268 != NULL) {
269 dll_destroy_with_data_memtype(
270 ((struct
271 pcep_object_tlv_speaker_entity_identifier *)
272 tlv)
273 ->speaker_entity_id_list,
274 PCEPLIB_MESSAGES);
275 }
276 break;
277
278 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
279 if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
280 ->pst_list
281 != NULL) {
282 dll_destroy_with_data_memtype(
283 ((struct
284 pcep_object_tlv_path_setup_type_capability *)
285 tlv)
286 ->pst_list,
287 PCEPLIB_MESSAGES);
288 }
289
290 if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
291 ->sub_tlv_list
292 != NULL) {
293 dll_destroy_with_data_memtype(
294 ((struct
295 pcep_object_tlv_path_setup_type_capability *)
296 tlv)
297 ->sub_tlv_list,
298 PCEPLIB_MESSAGES);
299 }
300 break;
301
302 default:
303 break;
304 }
305
306 pceplib_free(PCEPLIB_MESSAGES, tlv);
307}
308
309void pcep_obj_free_object(struct pcep_object_header *obj)
310{
311 /* Iterate the TLVs and free each one */
312 if (obj->tlv_list != NULL) {
313 struct pcep_object_tlv_header *tlv;
314 while ((tlv = (struct pcep_object_tlv_header *)
315 dll_delete_first_node(obj->tlv_list))
316 != NULL) {
317 pcep_obj_free_tlv(tlv);
318 }
319
320 dll_destroy(obj->tlv_list);
321 }
322
323 /* Specific object freeing */
324 switch (obj->object_class) {
325 case PCEP_OBJ_CLASS_ERO:
326 case PCEP_OBJ_CLASS_IRO:
327 case PCEP_OBJ_CLASS_RRO: {
328 if (((struct pcep_object_ro *)obj)->sub_objects != NULL) {
329 double_linked_list_node *node =
330 ((struct pcep_object_ro *)obj)
331 ->sub_objects->head;
332 for (; node != NULL; node = node->next_node) {
333 struct pcep_object_ro_subobj *ro_subobj =
334 (struct pcep_object_ro_subobj *)
335 node->data;
336 if (ro_subobj->ro_subobj_type
337 == RO_SUBOBJ_TYPE_SR) {
338 if (((struct pcep_ro_subobj_sr *)
339 ro_subobj)
340 ->nai_list
341 != NULL) {
342 dll_destroy_with_data_memtype(
343 ((struct
344 pcep_ro_subobj_sr *)
345 ro_subobj)
346 ->nai_list,
347 PCEPLIB_MESSAGES);
348 }
349 }
350 }
351 dll_destroy_with_data_memtype(
352 ((struct pcep_object_ro *)obj)->sub_objects,
353 PCEPLIB_MESSAGES);
354 }
355 } break;
356
357 case PCEP_OBJ_CLASS_SVEC:
358 if (((struct pcep_object_svec *)obj)->request_id_list != NULL) {
359 dll_destroy_with_data_memtype(
360 ((struct pcep_object_svec *)obj)
361 ->request_id_list,
362 PCEPLIB_MESSAGES);
363 }
364 break;
365
366 case PCEP_OBJ_CLASS_SWITCH_LAYER:
367 if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows
368 != NULL) {
369 dll_destroy_with_data_memtype(
370 ((struct pcep_object_switch_layer *)obj)
371 ->switch_layer_rows,
372 PCEPLIB_MESSAGES);
373 }
374 break;
375
376 default:
377 break;
378 }
379
380 pceplib_free(PCEPLIB_MESSAGES, obj);
381}
382
383void pcep_msg_free_message(struct pcep_message *message)
384{
385 /* Iterate the objects and free each one */
386 if (message->obj_list != NULL) {
387 struct pcep_object_header *obj;
388 while ((obj = (struct pcep_object_header *)
389 dll_delete_first_node(message->obj_list))
390 != NULL) {
391 pcep_obj_free_object(obj);
392 }
393
394 dll_destroy(message->obj_list);
395 }
396
397 if (message->msg_header != NULL) {
398 pceplib_free(PCEPLIB_MESSAGES, message->msg_header);
399 }
400
401 if (message->encoded_message != NULL) {
402 pceplib_free(PCEPLIB_MESSAGES, message->encoded_message);
403 }
404
405 pceplib_free(PCEPLIB_MESSAGES, message);
406}
407
408void pcep_msg_free_message_list(double_linked_list *list)
409{
410 /* Iterate the messages and free each one */
411 struct pcep_message *msg;
412 while ((msg = (struct pcep_message *)dll_delete_first_node(list))
413 != NULL) {
414 pcep_msg_free_message(msg);
415 }
416
417 dll_destroy(list);
418}
419
420const char *get_message_type_str(uint8_t type)
421{
422 uint8_t msg_type =
423 (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type;
424
425 return message_type_strs[msg_type];
426}
427
428const char *get_object_class_str(uint8_t class)
429{
430 uint8_t object_class =
431 (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class;
432
433 return object_class_strs[object_class];
434}
435
436/* Expecting a list of struct pcep_message pointers */
437void pcep_msg_print(double_linked_list *msg_list)
438{
439 double_linked_list_node *node;
440 for (node = msg_list->head; node != NULL; node = node->next_node) {
441 struct pcep_message *msg = (struct pcep_message *)node->data;
442 pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__,
443 get_message_type_str(msg->msg_header->type));
444
445 double_linked_list_node *obj_node =
446 (msg->obj_list == NULL ? NULL : msg->obj_list->head);
447 for (; obj_node != NULL; obj_node = obj_node->next_node) {
448 struct pcep_object_header *obj_header =
449 ((struct pcep_object_header *)obj_node->data);
450 pcep_log(
451 LOG_INFO, "%s: PCEP_OBJ %s", __func__,
452 get_object_class_str(obj_header->object_class));
453 }
454 }
455}
456
457int pcep_msg_send(int sock_fd, struct pcep_message *msg)
458{
459 if (msg == NULL) {
460 return 0;
461 }
462
463 return write(sock_fd, msg->encoded_message,
464 ntohs(msg->encoded_message_length));
465}