]> git.proxmox.com Git - mirror_frr.git/blob - pceplib/pcep_session_logic_states.c
pceplib: Add missing enum's to switch statement
[mirror_frr.git] / pceplib / pcep_session_logic_states.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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <pthread.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32
33 #include "pcep_msg_encoding.h"
34 #include "pcep_session_logic.h"
35 #include "pcep_session_logic_internals.h"
36 #include "pcep_timers.h"
37 #include "pcep_utils_logging.h"
38 #include "pcep_utils_memory.h"
39
40 #define TIMER_OPEN_KEEP_ALIVE_SECONDS 1
41
42 /* Session Logic Handle managed in pcep_session_logic.c */
43 extern pcep_event_queue *session_logic_event_queue_;
44 void send_keep_alive(pcep_session *session);
45 void send_pcep_error_with_object(pcep_session *session,
46 enum pcep_error_type error_type,
47 enum pcep_error_value error_value,
48 struct pcep_object_header *object);
49 void reset_dead_timer(pcep_session *session);
50 bool verify_pcep_open_object(pcep_session *session,
51 struct pcep_object_open *open_object);
52 void send_reconciled_pcep_open(pcep_session *session,
53 struct pcep_message *error_msg);
54 bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg);
55 bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg);
56 bool check_and_send_open_keep_alive(pcep_session *session);
57 void log_pcc_pce_connection(pcep_session *session);
58 bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg);
59
60 /*
61 * util functions called by the state handling below
62 */
63
64 void send_keep_alive(pcep_session *session)
65 {
66 struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive();
67
68 pcep_log(
69 LOG_INFO,
70 "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]",
71 __func__, time(NULL), pthread_self(), session->session_id);
72
73 session_send_message(session, keep_alive_msg);
74
75 /* The keep alive timer will be (re)set once the message
76 * is sent in session_logic_message_sent_handler() */
77 }
78
79
80 /* Send an error message with the corrected or offending object */
81 void send_pcep_error_with_object(pcep_session *session,
82 enum pcep_error_type error_type,
83 enum pcep_error_value error_value,
84 struct pcep_object_header *object)
85 {
86 double_linked_list *obj_list = dll_initialize();
87 dll_append(obj_list, object);
88 struct pcep_message *error_msg = pcep_msg_create_error_with_objects(
89 error_type, error_value, obj_list);
90
91 pcep_log(
92 LOG_INFO,
93 "%s: [%ld-%ld] pcep_session_logic send error message with object [%d][%d] for session [%d]",
94 __func__, time(NULL), pthread_self(), error_type, error_value,
95 session->session_id);
96
97 session_send_message(session, error_msg);
98 }
99
100
101 void send_pcep_error(pcep_session *session, enum pcep_error_type error_type,
102 enum pcep_error_value error_value)
103 {
104 struct pcep_message *error_msg =
105 pcep_msg_create_error(error_type, error_value);
106
107 pcep_log(
108 LOG_INFO,
109 "%s: [%ld-%ld] pcep_session_logic send error message [%d][%d] for session [%d]",
110 __func__, time(NULL), pthread_self(), error_type, error_value,
111 session->session_id);
112
113 session_send_message(session, error_msg);
114 }
115
116
117 void reset_dead_timer(pcep_session *session)
118 {
119 /* Default to configured dead_timer if its not set yet or set to 0 by
120 * the PCE */
121 int dead_timer_seconds =
122 (session->pcc_config.dead_timer_pce_negotiated_seconds == 0)
123 ? session->pcc_config.dead_timer_seconds
124 : session->pcc_config.dead_timer_pce_negotiated_seconds;
125
126 if (session->timer_id_dead_timer == TIMER_ID_NOT_SET) {
127 session->timer_id_dead_timer =
128 create_timer(dead_timer_seconds, session);
129 pcep_log(
130 LOG_INFO,
131 "%s: [%ld-%ld] pcep_session_logic set dead timer [%d secs] id [%d] for session [%d]",
132 __func__, time(NULL), pthread_self(),
133 dead_timer_seconds, session->timer_id_dead_timer,
134 session->session_id);
135 } else {
136 pcep_log(
137 LOG_INFO,
138 "%s: [%ld-%ld] pcep_session_logic reset dead timer [%d secs] id [%d] for session [%d]",
139 __func__, time(NULL), pthread_self(),
140 dead_timer_seconds, session->timer_id_dead_timer,
141 session->session_id);
142 reset_timer(session->timer_id_dead_timer);
143 }
144 }
145
146
147 void enqueue_event(pcep_session *session, pcep_event_type event_type,
148 struct pcep_message *message)
149 {
150 if (event_type == MESSAGE_RECEIVED && message == NULL) {
151 pcep_log(
152 LOG_WARNING,
153 "%s: enqueue_event cannot enqueue a NULL message session [%d]",
154 __func__, session->session_id);
155 return;
156 }
157
158 pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event));
159 memset(event, 0, sizeof(pcep_event));
160
161 event->session = session;
162 event->event_type = event_type;
163 event->event_time = time(NULL);
164 event->message = message;
165
166 pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
167 if (session_logic_event_queue_->event_callback != NULL) {
168 session_logic_event_queue_->event_callback(
169 session_logic_event_queue_->event_callback_data, event);
170 } else {
171 queue_enqueue(session_logic_event_queue_->event_queue, event);
172 }
173 pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
174 }
175
176 /* Verify the received PCEP Open object parameters are acceptable. If not,
177 * update the unacceptable value(s) with an acceptable value so it can be sent
178 * back to the sender. */
179 bool verify_pcep_open_object(pcep_session *session,
180 struct pcep_object_open *open_object)
181 {
182 int retval = true;
183
184 if (open_object->open_keepalive
185 < session->pcc_config.min_keep_alive_seconds) {
186 pcep_log(
187 LOG_INFO,
188 "%s: Rejecting unsupported Open Keep Alive value [%d] min [%d]",
189 __func__, open_object->open_keepalive,
190 session->pcc_config.min_keep_alive_seconds);
191 open_object->open_keepalive =
192 session->pcc_config.min_keep_alive_seconds;
193 retval = false;
194 } else if (open_object->open_keepalive
195 > session->pcc_config.max_keep_alive_seconds) {
196 pcep_log(
197 LOG_INFO,
198 "%s: Rejecting unsupported Open Keep Alive value [%d] max [%d]",
199 __func__, open_object->open_keepalive,
200 session->pcc_config.max_keep_alive_seconds);
201 open_object->open_keepalive =
202 session->pcc_config.max_keep_alive_seconds;
203 retval = false;
204 }
205
206 if (open_object->open_deadtimer
207 < session->pcc_config.min_dead_timer_seconds) {
208 pcep_log(LOG_INFO,
209 "%s: Rejecting unsupported Open Dead Timer value [%d]",
210 __func__, open_object->open_deadtimer);
211 open_object->open_deadtimer =
212 session->pcc_config.min_dead_timer_seconds;
213 retval = false;
214 } else if (open_object->open_deadtimer
215 > session->pcc_config.max_dead_timer_seconds) {
216 pcep_log(LOG_INFO,
217 "%s: Rejecting unsupported Open Dead Timer value [%d]",
218 __func__, open_object->open_deadtimer);
219 open_object->open_deadtimer =
220 session->pcc_config.max_dead_timer_seconds;
221 retval = false;
222 }
223
224 /* Check for Open Object TLVs */
225 if (pcep_object_has_tlvs((struct pcep_object_header *)open_object)
226 == false) {
227 /* There are no TLVs, all done */
228 return retval;
229 }
230
231 double_linked_list_node *tlv_node = open_object->header.tlv_list->head;
232 while (tlv_node != NULL) {
233 struct pcep_object_tlv_header *tlv = tlv_node->data;
234 tlv_node = tlv_node->next_node;
235
236 /* Supported Open Object TLVs */
237 switch (tlv->type) {
238 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION:
239 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
240 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
241 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
242 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
243 break;
244
245 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR:
246 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST:
247 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO:
248 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME:
249 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS:
250 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS:
251 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE:
252 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC:
253 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
254 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID:
255 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME:
256 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID:
257 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE:
258 case PCEP_OBJ_TLV_TYPE_UNKNOWN:
259 case PCEP_OBJ_TYPE_CISCO_BSID:
260 case PCEP_OBJ_TLV_TYPE_ARBITRARY:
261 /* TODO how to handle unrecognized TLV ?? */
262 pcep_log(
263 LOG_INFO,
264 "%s: Unhandled OPEN Object TLV type: %d, length %d",
265 __func__, tlv->type, tlv->encoded_tlv_length);
266 break;
267 }
268
269 /* Verify the STATEFUL-PCE-CAPABILITY TLV */
270 if (tlv->type == PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY) {
271 struct pcep_object_tlv_stateful_pce_capability
272 *pce_cap_tlv =
273 (struct
274 pcep_object_tlv_stateful_pce_capability
275 *)tlv;
276
277 /* If the U flag is set, then the PCE is
278 * capable of updating LSP parameters */
279 if (pce_cap_tlv->flag_u_lsp_update_capability) {
280 if (session->pce_config
281 .support_stateful_pce_lsp_update
282 == false) {
283 /* Turn off the U bit, as it is not
284 * supported */
285 pcep_log(
286 LOG_INFO,
287 "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
288 __func__);
289 pce_cap_tlv
290 ->flag_u_lsp_update_capability =
291 false;
292 retval = false;
293 } else {
294 session->stateful_pce = true;
295 pcep_log(
296 LOG_INFO,
297 "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
298 __func__, session->session_id);
299 }
300 }
301 /* TODO the rest of the flags are not implemented yet */
302 else if (pce_cap_tlv->flag_s_include_db_version) {
303 pcep_log(
304 LOG_INFO,
305 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
306 __func__);
307 } else if (
308 pce_cap_tlv
309 ->flag_i_lsp_instantiation_capability) {
310 pcep_log(
311 LOG_INFO,
312 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
313 __func__);
314 } else if (pce_cap_tlv->flag_t_triggered_resync) {
315 pcep_log(
316 LOG_INFO,
317 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
318 __func__);
319 } else if (pce_cap_tlv->flag_d_delta_lsp_sync) {
320 pcep_log(
321 LOG_INFO,
322 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
323 __func__);
324 } else if (pce_cap_tlv->flag_f_triggered_initial_sync) {
325 pcep_log(
326 LOG_INFO,
327 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
328 __func__);
329 }
330 } else if (tlv->type == PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION) {
331 if (session->pce_config.support_include_db_version
332 == false) {
333 pcep_log(
334 LOG_INFO,
335 "%s: Rejecting unsupported Open LSP DB VERSION TLV",
336 __func__);
337 /* Remove this TLV from the list */
338 dll_delete_node(open_object->header.tlv_list,
339 tlv_node);
340 retval = false;
341 }
342 }
343 }
344
345 return retval;
346 }
347
348
349 bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg)
350 {
351 /* Open Message validation and errors according to:
352 * https://tools.ietf.org/html/rfc5440#section-7.15 */
353
354 if (session->session_state != SESSION_STATE_PCEP_CONNECTING
355 && session->session_state != SESSION_STATE_INITIALIZED) {
356 pcep_log(
357 LOG_INFO,
358 "%s: Received unexpected OPEN, current session state [%d, replying with error]",
359 __func__, session->session_state);
360 send_pcep_error(session,
361 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
362 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
363 return false;
364 }
365
366 if (session->pce_open_received == true
367 && session->pce_open_rejected == false) {
368 pcep_log(LOG_INFO,
369 "%s: Received duplicate OPEN, replying with error",
370 __func__);
371 send_pcep_error(session,
372 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
373 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
374 return false;
375 }
376
377 struct pcep_object_open *open_object =
378 (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
379 PCEP_OBJ_CLASS_OPEN);
380 if (open_object == NULL) {
381 pcep_log(
382 LOG_INFO,
383 "%s: Received OPEN message with no OPEN object, replying with error",
384 __func__);
385 send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
386 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
387 return false;
388 }
389
390 /* Check for additional Open Msg objects */
391 if (open_msg->obj_list->num_entries > 1) {
392 pcep_log(
393 LOG_INFO,
394 "%s: Found additional unsupported objects in the Open message, replying with error",
395 __func__);
396 send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
397 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
398 return false;
399 }
400
401 session->pce_open_received = true;
402
403 /* Verify the open object parameters and TLVs */
404 if (verify_pcep_open_object(session, open_object) == false) {
405 enqueue_event(session, PCC_RCVD_INVALID_OPEN, NULL);
406 if (session->pce_open_rejected) {
407 /* The Open message was already rejected once, so
408 * according to the spec, send an error message and
409 * close the TCP connection. */
410 pcep_log(
411 LOG_INFO,
412 "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
413 __func__);
414 send_pcep_error(
415 session, PCEP_ERRT_SESSION_FAILURE,
416 PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE);
417 socket_comm_session_close_tcp_after_write(
418 session->socket_comm_session);
419 session->session_state = SESSION_STATE_INITIALIZED;
420 enqueue_event(session, PCC_CONNECTION_FAILURE, NULL);
421 } else {
422 session->pce_open_rejected = true;
423 /* Clone the object here, since the encapsulating
424 * message will be deleted in handle_socket_comm_event()
425 * most likely before this error message is sent */
426 struct pcep_object_open *cloned_open_object =
427 pceplib_malloc(PCEPLIB_MESSAGES,
428 sizeof(struct pcep_object_open));
429 memcpy(cloned_open_object, open_object,
430 sizeof(struct pcep_object_open));
431 open_object->header.tlv_list = NULL;
432 cloned_open_object->header.encoded_object = NULL;
433 cloned_open_object->header.encoded_object_length = 0;
434 send_pcep_error_with_object(
435 session, PCEP_ERRT_SESSION_FAILURE,
436 PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG,
437 &cloned_open_object->header);
438 }
439
440 return false;
441 }
442
443 /*
444 * Open Message accepted
445 * Sending the keep-alive response will be managed the function caller
446 */
447
448 session->timer_id_open_keep_alive =
449 create_timer(TIMER_OPEN_KEEP_ALIVE_SECONDS, session);
450 session->pcc_config.dead_timer_pce_negotiated_seconds =
451 (int)open_object->open_deadtimer;
452 /* Cancel the timer so we can change the dead_timer value */
453 cancel_timer(session->timer_id_dead_timer);
454 session->timer_id_dead_timer = TIMER_ID_NOT_SET;
455 reset_dead_timer(session);
456
457 return true;
458 }
459
460
461 /* The original PCEP Open message sent to the PCE was rejected,
462 * try to reconcile the differences and re-send a new Open. */
463 void send_reconciled_pcep_open(pcep_session *session,
464 struct pcep_message *error_msg)
465 {
466 struct pcep_message *open_msg = create_pcep_open(session);
467
468 struct pcep_object_open *error_open_obj =
469 (struct pcep_object_open *)pcep_obj_get(error_msg->obj_list,
470 PCEP_OBJ_CLASS_OPEN);
471 if (error_open_obj == NULL) {
472 /* Nothing to reconcile, send the same Open message again */
473 pcep_log(
474 LOG_INFO,
475 "%s: No Open object received in Error, sending the same Open message",
476 __func__);
477 session_send_message(session, open_msg);
478 return;
479 }
480
481 struct pcep_object_open *open_obj =
482 (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
483 PCEP_OBJ_CLASS_OPEN);
484 // open_msg can not have empty obj_list
485 assert(open_obj != NULL);
486
487 if (error_open_obj->open_deadtimer
488 != session->pce_config.dead_timer_seconds) {
489 if (error_open_obj->open_deadtimer
490 >= session->pce_config.min_dead_timer_seconds
491 && error_open_obj->open_deadtimer
492 <= session->pce_config.max_dead_timer_seconds) {
493 open_obj->open_deadtimer =
494 error_open_obj->open_deadtimer;
495 session->pcc_config.dead_timer_pce_negotiated_seconds =
496 error_open_obj->open_deadtimer;
497 pcep_log(
498 LOG_INFO,
499 "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
500 __func__,
501 session->pcc_config.dead_timer_seconds,
502 session->pcc_config
503 .dead_timer_pce_negotiated_seconds);
504 /* Reset the timer with the new value */
505 cancel_timer(session->timer_id_dead_timer);
506 session->timer_id_dead_timer = TIMER_ID_NOT_SET;
507 reset_dead_timer(session);
508 } else {
509 pcep_log(
510 LOG_INFO,
511 "%s: Can not reconcile Open with suggested deadtimer [%d]",
512 __func__, error_open_obj->open_deadtimer);
513 }
514 }
515
516 if (error_open_obj->open_keepalive
517 != session->pce_config.keep_alive_seconds) {
518 if (error_open_obj->open_keepalive
519 >= session->pce_config.min_keep_alive_seconds
520 && error_open_obj->open_keepalive
521 <= session->pce_config.max_keep_alive_seconds) {
522 open_obj->open_keepalive =
523 error_open_obj->open_keepalive;
524 session->pcc_config
525 .keep_alive_pce_negotiated_timer_seconds =
526 error_open_obj->open_keepalive;
527 pcep_log(
528 LOG_INFO,
529 "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
530 __func__,
531 session->pcc_config.keep_alive_seconds,
532 session->pcc_config
533 .keep_alive_pce_negotiated_timer_seconds);
534 /* Cancel the timer, the timer will be set again with
535 * the new value when this open message is sent */
536 cancel_timer(session->timer_id_keep_alive);
537 session->timer_id_keep_alive = TIMER_ID_NOT_SET;
538 } else {
539 pcep_log(
540 LOG_INFO,
541 "%s: Can not reconcile Open with suggested keepalive [%d]",
542 __func__, error_open_obj->open_keepalive);
543 }
544 }
545
546 /* TODO reconcile the TLVs */
547
548 session_send_message(session, open_msg);
549 reset_timer(session->timer_id_open_keep_alive);
550 }
551
552
553 bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg)
554 {
555 /* Update Message validation and errors according to:
556 * https://tools.ietf.org/html/rfc8231#section-6.2 */
557
558 if (upd_msg->obj_list == NULL) {
559 pcep_log(LOG_INFO,
560 "%s: Invalid PcUpd message: Message has no objects",
561 __func__);
562 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
563 PCEP_ERRV_SRP_OBJECT_MISSING);
564 return false;
565 }
566
567 /* Verify the mandatory objects are present */
568 struct pcep_object_header *obj =
569 pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_SRP);
570 if (obj == NULL) {
571 pcep_log(LOG_INFO,
572 "%s: Invalid PcUpd message: Missing SRP object",
573 __func__);
574 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
575 PCEP_ERRV_SRP_OBJECT_MISSING);
576 return false;
577 }
578
579 obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_LSP);
580 if (obj == NULL) {
581 pcep_log(LOG_INFO,
582 "%s: Invalid PcUpd message: Missing LSP object",
583 __func__);
584 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
585 PCEP_ERRV_LSP_OBJECT_MISSING);
586 return false;
587 }
588
589 obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_ERO);
590 if (obj == NULL) {
591 pcep_log(LOG_INFO,
592 "%s: Invalid PcUpd message: Missing ERO object",
593 __func__);
594 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
595 PCEP_ERRV_ERO_OBJECT_MISSING);
596 return false;
597 }
598
599 /* Verify the objects are are in the correct order */
600 double_linked_list_node *node = upd_msg->obj_list->head;
601 struct pcep_object_srp *srp_object =
602 (struct pcep_object_srp *)node->data;
603 if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) {
604 pcep_log(
605 LOG_INFO,
606 "%s: Invalid PcUpd message: First object must be an SRP, found [%d]",
607 __func__, srp_object->header.object_class);
608 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
609 PCEP_ERRV_SRP_OBJECT_MISSING);
610 return false;
611 }
612
613 node = node->next_node;
614 struct pcep_object_lsp *lsp_object =
615 (struct pcep_object_lsp *)node->data;
616 if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) {
617 pcep_log(
618 LOG_INFO,
619 "%s: Invalid PcUpd message: Second object must be an LSP, found [%d]",
620 __func__, lsp_object->header.object_class);
621 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
622 PCEP_ERRV_LSP_OBJECT_MISSING);
623 return false;
624 }
625
626 node = node->next_node;
627 struct pcep_object_ro *ero_object = node->data;
628 if (ero_object->header.object_class != PCEP_OBJ_CLASS_ERO) {
629 pcep_log(
630 LOG_INFO,
631 "%s: Invalid PcUpd message: Third object must be an ERO, found [%d]",
632 __func__, ero_object->header.object_class);
633 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
634 PCEP_ERRV_ERO_OBJECT_MISSING);
635 return false;
636 }
637
638 return true;
639 }
640
641 bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg)
642 {
643 /* Instantiate Message validation and errors according to:
644 * https://tools.ietf.org/html/rfc8281#section-5 */
645
646 if (init_msg->obj_list == NULL) {
647 pcep_log(
648 LOG_INFO,
649 "%s: Invalid PcInitiate message: Message has no objects",
650 __func__);
651 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
652 PCEP_ERRV_SRP_OBJECT_MISSING);
653 return false;
654 }
655
656 /* Verify the mandatory objects are present */
657 struct pcep_object_header *obj =
658 pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_SRP);
659 if (obj == NULL) {
660 pcep_log(LOG_INFO,
661 "%s: Invalid PcInitiate message: Missing SRP object",
662 __func__);
663 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
664 PCEP_ERRV_SRP_OBJECT_MISSING);
665 return false;
666 }
667
668 obj = pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_LSP);
669 if (obj == NULL) {
670 pcep_log(LOG_INFO,
671 "%s: Invalid PcInitiate message: Missing LSP object",
672 __func__);
673 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
674 PCEP_ERRV_LSP_OBJECT_MISSING);
675 return false;
676 }
677
678 /* Verify the objects are are in the correct order */
679 double_linked_list_node *node = init_msg->obj_list->head;
680 struct pcep_object_srp *srp_object =
681 (struct pcep_object_srp *)node->data;
682 if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) {
683 pcep_log(
684 LOG_INFO,
685 "%s: Invalid PcInitiate message: First object must be an SRP, found [%d]",
686 __func__, srp_object->header.object_class);
687 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
688 PCEP_ERRV_SRP_OBJECT_MISSING);
689 return false;
690 }
691
692 node = node->next_node;
693 struct pcep_object_lsp *lsp_object =
694 (struct pcep_object_lsp *)node->data;
695 if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) {
696 pcep_log(
697 LOG_INFO,
698 "%s: Invalid PcInitiate message: Second object must be an LSP, found [%d]",
699 __func__, lsp_object->header.object_class);
700 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
701 PCEP_ERRV_LSP_OBJECT_MISSING);
702 return false;
703 }
704
705 /* There may be more optional objects */
706 return true;
707 }
708
709 void increment_unknown_message(pcep_session *session)
710 {
711 /* https://tools.ietf.org/html/rfc5440#section-6.9
712 * If a PCC/PCE receives unrecognized messages at a rate equal or
713 * greater than MAX-UNKNOWN-MESSAGES unknown message requests per
714 * minute, the PCC/PCE MUST send a PCEP CLOSE message */
715
716 time_t *unknown_message_time =
717 pceplib_malloc(PCEPLIB_INFRA, sizeof(time_t));
718 *unknown_message_time = time(NULL);
719 time_t expire_time = *unknown_message_time + 60;
720 queue_enqueue(session->num_unknown_messages_time_queue,
721 unknown_message_time);
722
723 /* Purge any entries older than 1 minute. The oldest entries are at the
724 * queue head */
725 queue_node *time_node = session->num_unknown_messages_time_queue->head;
726 while (time_node != NULL) {
727 if (*((time_t *)time_node->data) > expire_time) {
728 pceplib_free(
729 PCEPLIB_INFRA,
730 queue_dequeue(
731 session->num_unknown_messages_time_queue));
732 time_node =
733 session->num_unknown_messages_time_queue->head;
734 } else {
735 time_node = NULL;
736 }
737 }
738
739 if ((int)session->num_unknown_messages_time_queue->num_entries
740 >= session->pcc_config.max_unknown_messages) {
741 pcep_log(
742 LOG_INFO,
743 "%s: [%ld-%ld] Max unknown messages reached [%d] closing session [%d]",
744 __func__, time(NULL), pthread_self(),
745 session->pcc_config.max_unknown_messages,
746 session->session_id);
747
748 close_pcep_session_with_reason(session,
749 PCEP_CLOSE_REASON_UNREC_MSG);
750 enqueue_event(session, PCC_RCVD_MAX_UNKOWN_MSGS, NULL);
751 }
752 }
753
754 bool check_and_send_open_keep_alive(pcep_session *session)
755 {
756 if (session->pce_open_received == true
757 && session->pce_open_rejected == false
758 && session->pce_open_keep_alive_sent == false) {
759 /* Send the PCE Open keep-alive response if it hasnt been sent
760 * yet */
761 cancel_timer(session->timer_id_open_keep_alive);
762 session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
763 send_keep_alive(session);
764 session->pce_open_keep_alive_sent = true;
765
766 return true;
767 }
768
769 return false;
770 }
771
772 void log_pcc_pce_connection(pcep_session *session)
773 {
774 if (session->socket_comm_session == NULL) {
775 /* This only happens in UT */
776 return;
777 }
778
779 char src_ip_buf[40] = {0}, dst_ip_buf[40] = {0};
780 uint16_t src_port, dst_port;
781
782 if (session->socket_comm_session->is_ipv6) {
783 inet_ntop(AF_INET6,
784 &session->socket_comm_session->src_sock_addr
785 .src_sock_addr_ipv6.sin6_addr,
786 src_ip_buf, sizeof(src_ip_buf));
787 inet_ntop(AF_INET6,
788 &session->socket_comm_session->dest_sock_addr
789 .dest_sock_addr_ipv6.sin6_addr,
790 dst_ip_buf, sizeof(dst_ip_buf));
791 src_port = htons(session->socket_comm_session->src_sock_addr
792 .src_sock_addr_ipv6.sin6_port);
793 dst_port = htons(session->socket_comm_session->dest_sock_addr
794 .dest_sock_addr_ipv6.sin6_port);
795 } else {
796 inet_ntop(AF_INET,
797 &session->socket_comm_session->src_sock_addr
798 .src_sock_addr_ipv4.sin_addr,
799 src_ip_buf, sizeof(src_ip_buf));
800 inet_ntop(AF_INET,
801 &session->socket_comm_session->dest_sock_addr
802 .dest_sock_addr_ipv4.sin_addr,
803 dst_ip_buf, sizeof(dst_ip_buf));
804 src_port = htons(session->socket_comm_session->src_sock_addr
805 .src_sock_addr_ipv4.sin_port);
806 dst_port = htons(session->socket_comm_session->dest_sock_addr
807 .dest_sock_addr_ipv4.sin_port);
808 }
809
810 pcep_log(
811 LOG_INFO,
812 "%s: [%ld-%ld] Successful PCC [%s:%d] connection to PCE [%s:%d] session [%d] fd [%d]",
813 __func__, time(NULL), pthread_self(), src_ip_buf, src_port,
814 dst_ip_buf, dst_port, session->session_id,
815 session->socket_comm_session->socket_fd);
816 }
817
818 /*
819 * these functions are called by session_logic_loop() from
820 * pcep_session_logic_loop.c these functions are executed in the
821 * session_logic_loop thread, and the mutex is locked before calling these
822 * functions, so they are thread safe.
823 */
824
825 /* state machine handling for expired timers */
826 void handle_timer_event(pcep_session_event *event)
827 {
828 if (event == NULL) {
829 pcep_log(LOG_INFO, "%s: handle_timer_event NULL event",
830 __func__);
831 return;
832 }
833
834 pcep_session *session = event->session;
835
836 pcep_log(
837 LOG_INFO,
838 "%s: [%ld-%ld] pcep_session_logic handle_timer_event: session [%d] event timer_id [%d] session timers [OKW, OKA, DT, KA] [%d, %d, %d, %d]",
839 __func__, time(NULL), pthread_self(), session->session_id,
840 event->expired_timer_id, session->timer_id_open_keep_wait,
841 session->timer_id_open_keep_alive, session->timer_id_dead_timer,
842 session->timer_id_keep_alive);
843
844 /*
845 * these timer expirations are independent of the session state
846 */
847 if (event->expired_timer_id == session->timer_id_dead_timer) {
848 session->timer_id_dead_timer = TIMER_ID_NOT_SET;
849 increment_event_counters(session,
850 PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER);
851 close_pcep_session_with_reason(session,
852 PCEP_CLOSE_REASON_DEADTIMER);
853 enqueue_event(session, PCE_DEAD_TIMER_EXPIRED, NULL);
854 return;
855 } else if (event->expired_timer_id == session->timer_id_keep_alive) {
856 session->timer_id_keep_alive = TIMER_ID_NOT_SET;
857 increment_event_counters(session,
858 PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE);
859 send_keep_alive(session);
860 return;
861 }
862
863 /*
864 * handle timers that depend on the session state
865 */
866 switch (session->session_state) {
867 case SESSION_STATE_PCEP_CONNECTING:
868 if (event->expired_timer_id
869 == session->timer_id_open_keep_wait) {
870 /* close the TCP session */
871 pcep_log(
872 LOG_INFO,
873 "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
874 __func__, session->session_id);
875 increment_event_counters(
876 session,
877 PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT);
878 socket_comm_session_close_tcp_after_write(
879 session->socket_comm_session);
880 session->session_state = SESSION_STATE_INITIALIZED;
881 session->timer_id_open_keep_wait = TIMER_ID_NOT_SET;
882 enqueue_event(session, PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED,
883 NULL);
884 }
885
886 if (event->expired_timer_id
887 == session->timer_id_open_keep_alive) {
888 increment_event_counters(
889 session,
890 PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE);
891 session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
892 if (check_and_send_open_keep_alive(session) == true) {
893 if (session->pcc_open_accepted == true
894 && session->session_state
895 != SESSION_STATE_PCEP_CONNECTED) {
896 log_pcc_pce_connection(session);
897 session->session_state =
898 SESSION_STATE_PCEP_CONNECTED;
899 increment_event_counters(
900 session,
901 PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
902 enqueue_event(session,
903 PCC_CONNECTED_TO_PCE,
904 NULL);
905 }
906 }
907 return;
908 }
909 break;
910
911 case SESSION_STATE_INITIALIZED:
912 case SESSION_STATE_PCEP_CONNECTED:
913 case SESSION_STATE_UNKNOWN:
914 pcep_log(
915 LOG_INFO,
916 "%s: handle_timer_event unrecognized state transition, timer_id [%d] state [%d] session [%d]",
917 __func__, event->expired_timer_id,
918 session->session_state, session->session_id);
919 break;
920 }
921 }
922
923 /* State machine handling for received messages.
924 * This event was created in session_logic_msg_ready_handler() in
925 * pcep_session_logic_loop.c */
926 void handle_socket_comm_event(pcep_session_event *event)
927 {
928 if (event == NULL) {
929 pcep_log(LOG_INFO, "%s: handle_socket_comm_event NULL event",
930 __func__);
931 return;
932 }
933
934 pcep_session *session = event->session;
935
936 pcep_log(
937 LOG_INFO,
938 "%s: [%ld-%ld] pcep_session_logic handle_socket_comm_event: session [%d] num messages [%d] socket_closed [%d]",
939 __func__, time(NULL), pthread_self(), session->session_id,
940 (event->received_msg_list == NULL
941 ? -1
942 : (int)event->received_msg_list->num_entries),
943 event->socket_closed);
944
945 /*
946 * independent of the session state
947 */
948 if (event->socket_closed) {
949 pcep_log(
950 LOG_INFO,
951 "%s: handle_socket_comm_event socket closed for session [%d]",
952 __func__, session->session_id);
953 socket_comm_session_close_tcp(session->socket_comm_session);
954 enqueue_event(session, PCE_CLOSED_SOCKET, NULL);
955 if (session->session_state == SESSION_STATE_PCEP_CONNECTING) {
956 enqueue_event(session, PCC_CONNECTION_FAILURE, NULL);
957 }
958 session->session_state = SESSION_STATE_INITIALIZED;
959 increment_event_counters(session,
960 PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
961 return;
962 }
963
964 reset_dead_timer(session);
965
966 if (event->received_msg_list == NULL) {
967 return;
968 }
969
970 /* Message received on socket */
971 double_linked_list_node *msg_node;
972 for (msg_node = event->received_msg_list->head; msg_node != NULL;
973 msg_node = msg_node->next_node) {
974 bool message_enqueued = false;
975 struct pcep_message *msg =
976 (struct pcep_message *)msg_node->data;
977 pcep_log(LOG_INFO, "%s: \t %s message", __func__,
978 get_message_type_str(msg->msg_header->type));
979
980 increment_message_rx_counters(session, msg);
981
982 switch (msg->msg_header->type) {
983 case PCEP_TYPE_OPEN:
984 /* handle_pcep_open() checks session state, and for
985 * duplicate erroneous open messages, and replies with
986 * error messages as needed. It also sets
987 * pce_open_received. */
988 if (handle_pcep_open(session, msg) == true) {
989 /* PCE Open Message Accepted */
990 enqueue_event(session, MESSAGE_RECEIVED, msg);
991 message_enqueued = true;
992 session->pce_open_accepted = true;
993 session->pce_open_rejected = false;
994 if (session->pcc_open_accepted) {
995 /* If both the PCC and PCE Opens are
996 * accepted, then the session is
997 * connected */
998
999 check_and_send_open_keep_alive(session);
1000 log_pcc_pce_connection(session);
1001 session->session_state =
1002 SESSION_STATE_PCEP_CONNECTED;
1003 increment_event_counters(
1004 session,
1005 PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
1006 enqueue_event(session,
1007 PCC_CONNECTED_TO_PCE,
1008 NULL);
1009 }
1010 }
1011 break;
1012
1013 case PCEP_TYPE_KEEPALIVE:
1014 if (session->session_state
1015 == SESSION_STATE_PCEP_CONNECTING) {
1016 /* PCC Open Message Accepted */
1017 cancel_timer(session->timer_id_open_keep_wait);
1018 session->timer_id_open_keep_wait =
1019 TIMER_ID_NOT_SET;
1020 session->pcc_open_accepted = true;
1021 session->pcc_open_rejected = false;
1022 check_and_send_open_keep_alive(session);
1023
1024 if (session->pce_open_accepted) {
1025 /* If both the PCC and PCE Opens are
1026 * accepted, then the session is
1027 * connected */
1028 log_pcc_pce_connection(session);
1029 session->session_state =
1030 SESSION_STATE_PCEP_CONNECTED;
1031 increment_event_counters(
1032 session,
1033 PCEP_EVENT_COUNTER_ID_PCC_CONNECT);
1034 enqueue_event(session,
1035 PCC_CONNECTED_TO_PCE,
1036 NULL);
1037 }
1038 }
1039 /* The dead_timer was already reset above, so nothing
1040 * extra to do here */
1041 break;
1042
1043 case PCEP_TYPE_PCREP:
1044 enqueue_event(session, MESSAGE_RECEIVED, msg);
1045 message_enqueued = true;
1046 break;
1047
1048 case PCEP_TYPE_CLOSE:
1049 session->session_state = SESSION_STATE_INITIALIZED;
1050 socket_comm_session_close_tcp(
1051 session->socket_comm_session);
1052 /* TODO should we also enqueue the message, so they can
1053 * see the reasons?? */
1054 enqueue_event(session, PCE_SENT_PCEP_CLOSE, NULL);
1055 /* TODO could this duplicate the disconnect counter with
1056 * socket close ?? */
1057 increment_event_counters(
1058 session, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
1059 break;
1060
1061 case PCEP_TYPE_PCREQ:
1062 /* The PCC does not support receiving PcReq messages */
1063 send_pcep_error(session,
1064 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
1065 PCEP_ERRV_UNASSIGNED);
1066 break;
1067
1068 case PCEP_TYPE_REPORT:
1069 /* The PCC does not support receiving Report messages */
1070 send_pcep_error(session,
1071 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
1072 PCEP_ERRV_UNASSIGNED);
1073 break;
1074
1075 case PCEP_TYPE_UPDATE:
1076 /* Should reply with a PcRpt */
1077 if (handle_pcep_update(session, msg) == true) {
1078 enqueue_event(session, MESSAGE_RECEIVED, msg);
1079 message_enqueued = true;
1080 }
1081 break;
1082
1083 case PCEP_TYPE_INITIATE:
1084 /* Should reply with a PcRpt */
1085 if (handle_pcep_initiate(session, msg) == true) {
1086 enqueue_event(session, MESSAGE_RECEIVED, msg);
1087 message_enqueued = true;
1088 }
1089 break;
1090
1091 case PCEP_TYPE_PCNOTF:
1092 enqueue_event(session, MESSAGE_RECEIVED, msg);
1093 message_enqueued = true;
1094 break;
1095
1096 case PCEP_TYPE_ERROR:
1097 if (msg->obj_list != NULL
1098 && msg->obj_list->num_entries > 0) {
1099 struct pcep_object_header *obj_hdr =
1100 pcep_obj_get(msg->obj_list,
1101 PCEP_OBJ_CLASS_ERROR);
1102 if (obj_hdr != NULL) {
1103 struct pcep_object_error *error_obj =
1104 (struct pcep_object_error *)
1105 obj_hdr;
1106 pcep_log(
1107 LOG_DEBUG,
1108 "%s: Error object [type, value] = [%s, %s]",
1109 __func__,
1110 get_error_type_str(
1111 error_obj->error_type),
1112 get_error_value_str(
1113 error_obj->error_type,
1114 error_obj
1115 ->error_value));
1116 }
1117 }
1118
1119 if (session->session_state
1120 == SESSION_STATE_PCEP_CONNECTING) {
1121 /* A PCC_CONNECTION_FAILURE event will be sent
1122 * when the socket is closed, if the state is
1123 * SESSION_STATE_PCEP_CONNECTING, in case the
1124 * PCE allows more than 2 failed open messages.
1125 */
1126 pcep_log(LOG_INFO,
1127 "%s: PCC Open message rejected by PCE",
1128 __func__);
1129 session->pcc_open_rejected = true;
1130 send_reconciled_pcep_open(session, msg);
1131 enqueue_event(session, PCC_SENT_INVALID_OPEN,
1132 NULL);
1133 }
1134 enqueue_event(session, MESSAGE_RECEIVED, msg);
1135 message_enqueued = true;
1136 break;
1137
1138 case PCEP_TYPE_START_TLS:
1139 case PCEP_TYPE_MAX:
1140 pcep_log(LOG_INFO, "%s: \t UnSupported message",
1141 __func__);
1142 send_pcep_error(session,
1143 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
1144 PCEP_ERRV_UNASSIGNED);
1145 increment_unknown_message(session);
1146 break;
1147 }
1148
1149 /* if the message was enqueued, dont free it yet */
1150 if (message_enqueued == false) {
1151 pcep_msg_free_message(msg);
1152 }
1153 }
1154 dll_destroy(event->received_msg_list);
1155 }