1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * This file is part of the PCEPlib, a PCEP protocol library.
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
7 * Author : Brady Johnson <brady@voltanet.io>
21 #include "pcep_msg_encoding.h"
22 #include "pcep_session_logic.h"
23 #include "pcep_session_logic_internals.h"
24 #include "pcep_timers.h"
25 #include "pcep_utils_logging.h"
26 #include "pcep_utils_memory.h"
28 #define TIMER_OPEN_KEEP_ALIVE_SECONDS 1
30 /* Session Logic Handle managed in pcep_session_logic.c */
31 extern pcep_event_queue
*session_logic_event_queue_
;
32 void send_keep_alive(pcep_session
*session
);
33 void send_pcep_error_with_object(pcep_session
*session
,
34 enum pcep_error_type error_type
,
35 enum pcep_error_value error_value
,
36 struct pcep_object_header
*object
);
37 void reset_dead_timer(pcep_session
*session
);
38 bool verify_pcep_open_object(pcep_session
*session
,
39 struct pcep_object_open
*open_object
);
40 void send_reconciled_pcep_open(pcep_session
*session
,
41 struct pcep_message
*error_msg
);
42 bool handle_pcep_update(pcep_session
*session
, struct pcep_message
*upd_msg
);
43 bool handle_pcep_initiate(pcep_session
*session
, struct pcep_message
*init_msg
);
44 bool check_and_send_open_keep_alive(pcep_session
*session
);
45 void log_pcc_pce_connection(pcep_session
*session
);
46 bool handle_pcep_open(pcep_session
*session
, struct pcep_message
*open_msg
);
49 * util functions called by the state handling below
52 void send_keep_alive(pcep_session
*session
)
54 struct pcep_message
*keep_alive_msg
= pcep_msg_create_keepalive();
58 "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]",
59 __func__
, time(NULL
), pthread_self(), session
->session_id
);
61 session_send_message(session
, keep_alive_msg
);
63 /* The keep alive timer will be (re)set once the message
64 * is sent in session_logic_message_sent_handler() */
68 /* Send an error message with the corrected or offending object */
69 void send_pcep_error_with_object(pcep_session
*session
,
70 enum pcep_error_type error_type
,
71 enum pcep_error_value error_value
,
72 struct pcep_object_header
*object
)
74 double_linked_list
*obj_list
= dll_initialize();
75 dll_append(obj_list
, object
);
76 struct pcep_message
*error_msg
= pcep_msg_create_error_with_objects(
77 error_type
, error_value
, obj_list
);
81 "%s: [%ld-%ld] pcep_session_logic send error message with object [%d][%d] for session [%d]",
82 __func__
, time(NULL
), pthread_self(), error_type
, error_value
,
85 session_send_message(session
, error_msg
);
89 void send_pcep_error(pcep_session
*session
, enum pcep_error_type error_type
,
90 enum pcep_error_value error_value
)
92 struct pcep_message
*error_msg
=
93 pcep_msg_create_error(error_type
, error_value
);
97 "%s: [%ld-%ld] pcep_session_logic send error message [%d][%d] for session [%d]",
98 __func__
, time(NULL
), pthread_self(), error_type
, error_value
,
101 session_send_message(session
, error_msg
);
105 void reset_dead_timer(pcep_session
*session
)
107 /* Default to configured dead_timer if its not set yet or set to 0 by
109 int dead_timer_seconds
=
110 (session
->pcc_config
.dead_timer_pce_negotiated_seconds
== 0)
111 ? session
->pcc_config
.dead_timer_seconds
112 : session
->pcc_config
.dead_timer_pce_negotiated_seconds
;
114 if (session
->timer_id_dead_timer
== TIMER_ID_NOT_SET
) {
115 session
->timer_id_dead_timer
=
116 create_timer(dead_timer_seconds
, session
);
119 "%s: [%ld-%ld] pcep_session_logic set dead timer [%d secs] id [%d] for session [%d]",
120 __func__
, time(NULL
), pthread_self(),
121 dead_timer_seconds
, session
->timer_id_dead_timer
,
122 session
->session_id
);
126 "%s: [%ld-%ld] pcep_session_logic reset dead timer [%d secs] id [%d] for session [%d]",
127 __func__
, time(NULL
), pthread_self(),
128 dead_timer_seconds
, session
->timer_id_dead_timer
,
129 session
->session_id
);
130 reset_timer(session
->timer_id_dead_timer
);
135 void enqueue_event(pcep_session
*session
, pcep_event_type event_type
,
136 struct pcep_message
*message
)
138 if (event_type
== MESSAGE_RECEIVED
&& message
== NULL
) {
141 "%s: enqueue_event cannot enqueue a NULL message session [%d]",
142 __func__
, session
->session_id
);
146 pcep_event
*event
= pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_event
));
147 memset(event
, 0, sizeof(pcep_event
));
149 event
->session
= session
;
150 event
->event_type
= event_type
;
151 event
->event_time
= time(NULL
);
152 event
->message
= message
;
154 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
155 if (session_logic_event_queue_
->event_callback
!= NULL
) {
156 session_logic_event_queue_
->event_callback(
157 session_logic_event_queue_
->event_callback_data
, event
);
159 queue_enqueue(session_logic_event_queue_
->event_queue
, event
);
161 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
164 /* Verify the received PCEP Open object parameters are acceptable. If not,
165 * update the unacceptable value(s) with an acceptable value so it can be sent
166 * back to the sender. */
167 bool verify_pcep_open_object(pcep_session
*session
,
168 struct pcep_object_open
*open_object
)
172 if (open_object
->open_keepalive
173 < session
->pcc_config
.min_keep_alive_seconds
) {
176 "%s: Rejecting unsupported Open Keep Alive value [%d] min [%d]",
177 __func__
, open_object
->open_keepalive
,
178 session
->pcc_config
.min_keep_alive_seconds
);
179 open_object
->open_keepalive
=
180 session
->pcc_config
.min_keep_alive_seconds
;
182 } else if (open_object
->open_keepalive
183 > session
->pcc_config
.max_keep_alive_seconds
) {
186 "%s: Rejecting unsupported Open Keep Alive value [%d] max [%d]",
187 __func__
, open_object
->open_keepalive
,
188 session
->pcc_config
.max_keep_alive_seconds
);
189 open_object
->open_keepalive
=
190 session
->pcc_config
.max_keep_alive_seconds
;
194 if (open_object
->open_deadtimer
195 < session
->pcc_config
.min_dead_timer_seconds
) {
197 "%s: Rejecting unsupported Open Dead Timer value [%d]",
198 __func__
, open_object
->open_deadtimer
);
199 open_object
->open_deadtimer
=
200 session
->pcc_config
.min_dead_timer_seconds
;
202 } else if (open_object
->open_deadtimer
203 > session
->pcc_config
.max_dead_timer_seconds
) {
205 "%s: Rejecting unsupported Open Dead Timer value [%d]",
206 __func__
, open_object
->open_deadtimer
);
207 open_object
->open_deadtimer
=
208 session
->pcc_config
.max_dead_timer_seconds
;
212 /* Check for Open Object TLVs */
213 if (pcep_object_has_tlvs((struct pcep_object_header
*)open_object
)
215 /* There are no TLVs, all done */
219 double_linked_list_node
*tlv_node
= open_object
->header
.tlv_list
->head
;
220 while (tlv_node
!= NULL
) {
221 struct pcep_object_tlv_header
*tlv
= tlv_node
->data
;
222 tlv_node
= tlv_node
->next_node
;
224 /* Supported Open Object TLVs */
226 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
:
227 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY
:
228 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID
:
229 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
:
230 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY
:
233 case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR
:
234 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST
:
235 case PCEP_OBJ_TLV_TYPE_VENDOR_INFO
:
236 case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME
:
237 case PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS
:
238 case PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS
:
239 case PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE
:
240 case PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC
:
241 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE
:
242 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID
:
243 case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME
:
244 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID
:
245 case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE
:
246 case PCEP_OBJ_TLV_TYPE_UNKNOWN
:
247 case PCEP_OBJ_TYPE_CISCO_BSID
:
248 case PCEP_OBJ_TLV_TYPE_ARBITRARY
:
249 /* TODO how to handle unrecognized TLV ?? */
252 "%s: Unhandled OPEN Object TLV type: %d, length %d",
253 __func__
, tlv
->type
, tlv
->encoded_tlv_length
);
257 /* Verify the STATEFUL-PCE-CAPABILITY TLV */
258 if (tlv
->type
== PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
) {
259 struct pcep_object_tlv_stateful_pce_capability
262 pcep_object_tlv_stateful_pce_capability
265 /* If the U flag is set, then the PCE is
266 * capable of updating LSP parameters */
267 if (pce_cap_tlv
->flag_u_lsp_update_capability
) {
268 if (session
->pce_config
269 .support_stateful_pce_lsp_update
271 /* Turn off the U bit, as it is not
275 "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
278 ->flag_u_lsp_update_capability
=
282 session
->stateful_pce
= true;
285 "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
286 __func__
, session
->session_id
);
289 /* TODO the rest of the flags are not implemented yet */
290 else if (pce_cap_tlv
->flag_s_include_db_version
) {
293 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
297 ->flag_i_lsp_instantiation_capability
) {
300 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
302 } else if (pce_cap_tlv
->flag_t_triggered_resync
) {
305 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
307 } else if (pce_cap_tlv
->flag_d_delta_lsp_sync
) {
310 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
312 } else if (pce_cap_tlv
->flag_f_triggered_initial_sync
) {
315 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
318 } else if (tlv
->type
== PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
) {
319 if (session
->pce_config
.support_include_db_version
323 "%s: Rejecting unsupported Open LSP DB VERSION TLV",
325 /* Remove this TLV from the list */
326 dll_delete_node(open_object
->header
.tlv_list
,
337 bool handle_pcep_open(pcep_session
*session
, struct pcep_message
*open_msg
)
339 /* Open Message validation and errors according to:
340 * https://tools.ietf.org/html/rfc5440#section-7.15 */
342 if (session
->session_state
!= SESSION_STATE_PCEP_CONNECTING
343 && session
->session_state
!= SESSION_STATE_INITIALIZED
) {
346 "%s: Received unexpected OPEN, current session state [%d, replying with error]",
347 __func__
, session
->session_state
);
348 send_pcep_error(session
,
349 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION
,
350 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
354 if (session
->pce_open_received
== true
355 && session
->pce_open_rejected
== false) {
357 "%s: Received duplicate OPEN, replying with error",
359 send_pcep_error(session
,
360 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION
,
361 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
365 struct pcep_object_open
*open_object
=
366 (struct pcep_object_open
*)pcep_obj_get(open_msg
->obj_list
,
367 PCEP_OBJ_CLASS_OPEN
);
368 if (open_object
== NULL
) {
371 "%s: Received OPEN message with no OPEN object, replying with error",
373 send_pcep_error(session
, PCEP_ERRT_SESSION_FAILURE
,
374 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
378 /* Check for additional Open Msg objects */
379 if (open_msg
->obj_list
->num_entries
> 1) {
382 "%s: Found additional unsupported objects in the Open message, replying with error",
384 send_pcep_error(session
, PCEP_ERRT_SESSION_FAILURE
,
385 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
389 session
->pce_open_received
= true;
391 /* Verify the open object parameters and TLVs */
392 if (verify_pcep_open_object(session
, open_object
) == false) {
393 enqueue_event(session
, PCC_RCVD_INVALID_OPEN
, NULL
);
394 if (session
->pce_open_rejected
) {
395 /* The Open message was already rejected once, so
396 * according to the spec, send an error message and
397 * close the TCP connection. */
400 "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
403 session
, PCEP_ERRT_SESSION_FAILURE
,
404 PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE
);
405 socket_comm_session_close_tcp_after_write(
406 session
->socket_comm_session
);
407 session
->session_state
= SESSION_STATE_INITIALIZED
;
408 enqueue_event(session
, PCC_CONNECTION_FAILURE
, NULL
);
410 session
->pce_open_rejected
= true;
411 /* Clone the object here, since the encapsulating
412 * message will be deleted in handle_socket_comm_event()
413 * most likely before this error message is sent */
414 struct pcep_object_open
*cloned_open_object
=
415 pceplib_malloc(PCEPLIB_MESSAGES
,
416 sizeof(struct pcep_object_open
));
417 memcpy(cloned_open_object
, open_object
,
418 sizeof(struct pcep_object_open
));
419 open_object
->header
.tlv_list
= NULL
;
420 cloned_open_object
->header
.encoded_object
= NULL
;
421 cloned_open_object
->header
.encoded_object_length
= 0;
422 send_pcep_error_with_object(
423 session
, PCEP_ERRT_SESSION_FAILURE
,
424 PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG
,
425 &cloned_open_object
->header
);
432 * Open Message accepted
433 * Sending the keep-alive response will be managed the function caller
436 session
->timer_id_open_keep_alive
=
437 create_timer(TIMER_OPEN_KEEP_ALIVE_SECONDS
, session
);
438 session
->pcc_config
.dead_timer_pce_negotiated_seconds
=
439 (int)open_object
->open_deadtimer
;
440 /* Cancel the timer so we can change the dead_timer value */
441 cancel_timer(session
->timer_id_dead_timer
);
442 session
->timer_id_dead_timer
= TIMER_ID_NOT_SET
;
443 reset_dead_timer(session
);
449 /* The original PCEP Open message sent to the PCE was rejected,
450 * try to reconcile the differences and re-send a new Open. */
451 void send_reconciled_pcep_open(pcep_session
*session
,
452 struct pcep_message
*error_msg
)
454 struct pcep_message
*open_msg
= create_pcep_open(session
);
456 struct pcep_object_open
*error_open_obj
=
457 (struct pcep_object_open
*)pcep_obj_get(error_msg
->obj_list
,
458 PCEP_OBJ_CLASS_OPEN
);
459 if (error_open_obj
== NULL
) {
460 /* Nothing to reconcile, send the same Open message again */
463 "%s: No Open object received in Error, sending the same Open message",
465 session_send_message(session
, open_msg
);
469 struct pcep_object_open
*open_obj
=
470 (struct pcep_object_open
*)pcep_obj_get(open_msg
->obj_list
,
471 PCEP_OBJ_CLASS_OPEN
);
472 // open_msg can not have empty obj_list
473 assert(open_obj
!= NULL
);
475 if (error_open_obj
->open_deadtimer
476 != session
->pce_config
.dead_timer_seconds
) {
477 if (error_open_obj
->open_deadtimer
478 >= session
->pce_config
.min_dead_timer_seconds
479 && error_open_obj
->open_deadtimer
480 <= session
->pce_config
.max_dead_timer_seconds
) {
481 open_obj
->open_deadtimer
=
482 error_open_obj
->open_deadtimer
;
483 session
->pcc_config
.dead_timer_pce_negotiated_seconds
=
484 error_open_obj
->open_deadtimer
;
487 "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
489 session
->pcc_config
.dead_timer_seconds
,
491 .dead_timer_pce_negotiated_seconds
);
492 /* Reset the timer with the new value */
493 cancel_timer(session
->timer_id_dead_timer
);
494 session
->timer_id_dead_timer
= TIMER_ID_NOT_SET
;
495 reset_dead_timer(session
);
499 "%s: Can not reconcile Open with suggested deadtimer [%d]",
500 __func__
, error_open_obj
->open_deadtimer
);
504 if (error_open_obj
->open_keepalive
505 != session
->pce_config
.keep_alive_seconds
) {
506 if (error_open_obj
->open_keepalive
507 >= session
->pce_config
.min_keep_alive_seconds
508 && error_open_obj
->open_keepalive
509 <= session
->pce_config
.max_keep_alive_seconds
) {
510 open_obj
->open_keepalive
=
511 error_open_obj
->open_keepalive
;
513 .keep_alive_pce_negotiated_timer_seconds
=
514 error_open_obj
->open_keepalive
;
517 "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
519 session
->pcc_config
.keep_alive_seconds
,
521 .keep_alive_pce_negotiated_timer_seconds
);
522 /* Cancel the timer, the timer will be set again with
523 * the new value when this open message is sent */
524 cancel_timer(session
->timer_id_keep_alive
);
525 session
->timer_id_keep_alive
= TIMER_ID_NOT_SET
;
529 "%s: Can not reconcile Open with suggested keepalive [%d]",
530 __func__
, error_open_obj
->open_keepalive
);
534 /* TODO reconcile the TLVs */
536 session_send_message(session
, open_msg
);
537 reset_timer(session
->timer_id_open_keep_alive
);
541 bool handle_pcep_update(pcep_session
*session
, struct pcep_message
*upd_msg
)
543 /* Update Message validation and errors according to:
544 * https://tools.ietf.org/html/rfc8231#section-6.2 */
546 if (upd_msg
->obj_list
== NULL
) {
548 "%s: Invalid PcUpd message: Message has no objects",
550 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
551 PCEP_ERRV_SRP_OBJECT_MISSING
);
555 /* Verify the mandatory objects are present */
556 struct pcep_object_header
*obj
=
557 pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_SRP
);
560 "%s: Invalid PcUpd message: Missing SRP object",
562 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
563 PCEP_ERRV_SRP_OBJECT_MISSING
);
567 obj
= pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_LSP
);
570 "%s: Invalid PcUpd message: Missing LSP object",
572 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
573 PCEP_ERRV_LSP_OBJECT_MISSING
);
577 obj
= pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_ERO
);
580 "%s: Invalid PcUpd message: Missing ERO object",
582 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
583 PCEP_ERRV_ERO_OBJECT_MISSING
);
587 /* Verify the objects are are in the correct order */
588 double_linked_list_node
*node
= upd_msg
->obj_list
->head
;
589 struct pcep_object_srp
*srp_object
=
590 (struct pcep_object_srp
*)node
->data
;
591 if (srp_object
->header
.object_class
!= PCEP_OBJ_CLASS_SRP
) {
594 "%s: Invalid PcUpd message: First object must be an SRP, found [%d]",
595 __func__
, srp_object
->header
.object_class
);
596 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
597 PCEP_ERRV_SRP_OBJECT_MISSING
);
601 node
= node
->next_node
;
602 struct pcep_object_lsp
*lsp_object
=
603 (struct pcep_object_lsp
*)node
->data
;
604 if (lsp_object
->header
.object_class
!= PCEP_OBJ_CLASS_LSP
) {
607 "%s: Invalid PcUpd message: Second object must be an LSP, found [%d]",
608 __func__
, lsp_object
->header
.object_class
);
609 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
610 PCEP_ERRV_LSP_OBJECT_MISSING
);
614 node
= node
->next_node
;
615 struct pcep_object_ro
*ero_object
= node
->data
;
616 if (ero_object
->header
.object_class
!= PCEP_OBJ_CLASS_ERO
) {
619 "%s: Invalid PcUpd message: Third object must be an ERO, found [%d]",
620 __func__
, ero_object
->header
.object_class
);
621 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
622 PCEP_ERRV_ERO_OBJECT_MISSING
);
629 bool handle_pcep_initiate(pcep_session
*session
, struct pcep_message
*init_msg
)
631 /* Instantiate Message validation and errors according to:
632 * https://tools.ietf.org/html/rfc8281#section-5 */
634 if (init_msg
->obj_list
== NULL
) {
637 "%s: Invalid PcInitiate message: Message has no objects",
639 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
640 PCEP_ERRV_SRP_OBJECT_MISSING
);
644 /* Verify the mandatory objects are present */
645 struct pcep_object_header
*obj
=
646 pcep_obj_get(init_msg
->obj_list
, PCEP_OBJ_CLASS_SRP
);
649 "%s: Invalid PcInitiate message: Missing SRP object",
651 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
652 PCEP_ERRV_SRP_OBJECT_MISSING
);
656 obj
= pcep_obj_get(init_msg
->obj_list
, PCEP_OBJ_CLASS_LSP
);
659 "%s: Invalid PcInitiate message: Missing LSP object",
661 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
662 PCEP_ERRV_LSP_OBJECT_MISSING
);
666 /* Verify the objects are are in the correct order */
667 double_linked_list_node
*node
= init_msg
->obj_list
->head
;
668 struct pcep_object_srp
*srp_object
=
669 (struct pcep_object_srp
*)node
->data
;
670 if (srp_object
->header
.object_class
!= PCEP_OBJ_CLASS_SRP
) {
673 "%s: Invalid PcInitiate message: First object must be an SRP, found [%d]",
674 __func__
, srp_object
->header
.object_class
);
675 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
676 PCEP_ERRV_SRP_OBJECT_MISSING
);
680 node
= node
->next_node
;
681 struct pcep_object_lsp
*lsp_object
=
682 (struct pcep_object_lsp
*)node
->data
;
683 if (lsp_object
->header
.object_class
!= PCEP_OBJ_CLASS_LSP
) {
686 "%s: Invalid PcInitiate message: Second object must be an LSP, found [%d]",
687 __func__
, lsp_object
->header
.object_class
);
688 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
689 PCEP_ERRV_LSP_OBJECT_MISSING
);
693 /* There may be more optional objects */
697 void increment_unknown_message(pcep_session
*session
)
699 /* https://tools.ietf.org/html/rfc5440#section-6.9
700 * If a PCC/PCE receives unrecognized messages at a rate equal or
701 * greater than MAX-UNKNOWN-MESSAGES unknown message requests per
702 * minute, the PCC/PCE MUST send a PCEP CLOSE message */
704 time_t *unknown_message_time
=
705 pceplib_malloc(PCEPLIB_INFRA
, sizeof(time_t));
706 *unknown_message_time
= time(NULL
);
707 time_t expire_time
= *unknown_message_time
+ 60;
708 queue_enqueue(session
->num_unknown_messages_time_queue
,
709 unknown_message_time
);
711 /* Purge any entries older than 1 minute. The oldest entries are at the
713 queue_node
*time_node
= session
->num_unknown_messages_time_queue
->head
;
714 while (time_node
!= NULL
) {
715 if (*((time_t *)time_node
->data
) > expire_time
) {
719 session
->num_unknown_messages_time_queue
));
721 session
->num_unknown_messages_time_queue
->head
;
727 if ((int)session
->num_unknown_messages_time_queue
->num_entries
728 >= session
->pcc_config
.max_unknown_messages
) {
731 "%s: [%ld-%ld] Max unknown messages reached [%d] closing session [%d]",
732 __func__
, time(NULL
), pthread_self(),
733 session
->pcc_config
.max_unknown_messages
,
734 session
->session_id
);
736 close_pcep_session_with_reason(session
,
737 PCEP_CLOSE_REASON_UNREC_MSG
);
738 enqueue_event(session
, PCC_RCVD_MAX_UNKOWN_MSGS
, NULL
);
742 bool check_and_send_open_keep_alive(pcep_session
*session
)
744 if (session
->pce_open_received
== true
745 && session
->pce_open_rejected
== false
746 && session
->pce_open_keep_alive_sent
== false) {
747 /* Send the PCE Open keep-alive response if it hasnt been sent
749 cancel_timer(session
->timer_id_open_keep_alive
);
750 session
->timer_id_open_keep_alive
= TIMER_ID_NOT_SET
;
751 send_keep_alive(session
);
752 session
->pce_open_keep_alive_sent
= true;
760 void log_pcc_pce_connection(pcep_session
*session
)
762 if (session
->socket_comm_session
== NULL
) {
763 /* This only happens in UT */
767 char src_ip_buf
[40] = {0}, dst_ip_buf
[40] = {0};
768 uint16_t src_port
, dst_port
;
770 if (session
->socket_comm_session
->is_ipv6
) {
772 &session
->socket_comm_session
->src_sock_addr
773 .src_sock_addr_ipv6
.sin6_addr
,
774 src_ip_buf
, sizeof(src_ip_buf
));
776 &session
->socket_comm_session
->dest_sock_addr
777 .dest_sock_addr_ipv6
.sin6_addr
,
778 dst_ip_buf
, sizeof(dst_ip_buf
));
779 src_port
= htons(session
->socket_comm_session
->src_sock_addr
780 .src_sock_addr_ipv6
.sin6_port
);
781 dst_port
= htons(session
->socket_comm_session
->dest_sock_addr
782 .dest_sock_addr_ipv6
.sin6_port
);
785 &session
->socket_comm_session
->src_sock_addr
786 .src_sock_addr_ipv4
.sin_addr
,
787 src_ip_buf
, sizeof(src_ip_buf
));
789 &session
->socket_comm_session
->dest_sock_addr
790 .dest_sock_addr_ipv4
.sin_addr
,
791 dst_ip_buf
, sizeof(dst_ip_buf
));
792 src_port
= htons(session
->socket_comm_session
->src_sock_addr
793 .src_sock_addr_ipv4
.sin_port
);
794 dst_port
= htons(session
->socket_comm_session
->dest_sock_addr
795 .dest_sock_addr_ipv4
.sin_port
);
800 "%s: [%ld-%ld] Successful PCC [%s:%d] connection to PCE [%s:%d] session [%d] fd [%d]",
801 __func__
, time(NULL
), pthread_self(), src_ip_buf
, src_port
,
802 dst_ip_buf
, dst_port
, session
->session_id
,
803 session
->socket_comm_session
->socket_fd
);
807 * these functions are called by session_logic_loop() from
808 * pcep_session_logic_loop.c these functions are executed in the
809 * session_logic_loop thread, and the mutex is locked before calling these
810 * functions, so they are thread safe.
813 /* state machine handling for expired timers */
814 void handle_timer_event(pcep_session_event
*event
)
817 pcep_log(LOG_INFO
, "%s: handle_timer_event NULL event",
822 pcep_session
*session
= event
->session
;
826 "%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]",
827 __func__
, time(NULL
), pthread_self(), session
->session_id
,
828 event
->expired_timer_id
, session
->timer_id_open_keep_wait
,
829 session
->timer_id_open_keep_alive
, session
->timer_id_dead_timer
,
830 session
->timer_id_keep_alive
);
833 * these timer expirations are independent of the session state
835 if (event
->expired_timer_id
== session
->timer_id_dead_timer
) {
836 session
->timer_id_dead_timer
= TIMER_ID_NOT_SET
;
837 increment_event_counters(session
,
838 PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER
);
839 close_pcep_session_with_reason(session
,
840 PCEP_CLOSE_REASON_DEADTIMER
);
841 enqueue_event(session
, PCE_DEAD_TIMER_EXPIRED
, NULL
);
843 } else if (event
->expired_timer_id
== session
->timer_id_keep_alive
) {
844 session
->timer_id_keep_alive
= TIMER_ID_NOT_SET
;
845 increment_event_counters(session
,
846 PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE
);
847 send_keep_alive(session
);
852 * handle timers that depend on the session state
854 switch (session
->session_state
) {
855 case SESSION_STATE_PCEP_CONNECTING
:
856 if (event
->expired_timer_id
857 == session
->timer_id_open_keep_wait
) {
858 /* close the TCP session */
861 "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
862 __func__
, session
->session_id
);
863 increment_event_counters(
865 PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT
);
866 socket_comm_session_close_tcp_after_write(
867 session
->socket_comm_session
);
868 session
->session_state
= SESSION_STATE_INITIALIZED
;
869 session
->timer_id_open_keep_wait
= TIMER_ID_NOT_SET
;
870 enqueue_event(session
, PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED
,
874 if (event
->expired_timer_id
875 == session
->timer_id_open_keep_alive
) {
876 increment_event_counters(
878 PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE
);
879 session
->timer_id_open_keep_alive
= TIMER_ID_NOT_SET
;
880 if (check_and_send_open_keep_alive(session
) == true) {
881 if (session
->pcc_open_accepted
== true
882 && session
->session_state
883 != SESSION_STATE_PCEP_CONNECTED
) {
884 log_pcc_pce_connection(session
);
885 session
->session_state
=
886 SESSION_STATE_PCEP_CONNECTED
;
887 increment_event_counters(
889 PCEP_EVENT_COUNTER_ID_PCE_CONNECT
);
890 enqueue_event(session
,
891 PCC_CONNECTED_TO_PCE
,
899 case SESSION_STATE_INITIALIZED
:
900 case SESSION_STATE_PCEP_CONNECTED
:
901 case SESSION_STATE_UNKNOWN
:
904 "%s: handle_timer_event unrecognized state transition, timer_id [%d] state [%d] session [%d]",
905 __func__
, event
->expired_timer_id
,
906 session
->session_state
, session
->session_id
);
911 /* State machine handling for received messages.
912 * This event was created in session_logic_msg_ready_handler() in
913 * pcep_session_logic_loop.c */
914 void handle_socket_comm_event(pcep_session_event
*event
)
917 pcep_log(LOG_INFO
, "%s: handle_socket_comm_event NULL event",
922 pcep_session
*session
= event
->session
;
926 "%s: [%ld-%ld] pcep_session_logic handle_socket_comm_event: session [%d] num messages [%d] socket_closed [%d]",
927 __func__
, time(NULL
), pthread_self(), session
->session_id
,
928 (event
->received_msg_list
== NULL
930 : (int)event
->received_msg_list
->num_entries
),
931 event
->socket_closed
);
934 * independent of the session state
936 if (event
->socket_closed
) {
939 "%s: handle_socket_comm_event socket closed for session [%d]",
940 __func__
, session
->session_id
);
941 socket_comm_session_close_tcp(session
->socket_comm_session
);
942 enqueue_event(session
, PCE_CLOSED_SOCKET
, NULL
);
943 if (session
->session_state
== SESSION_STATE_PCEP_CONNECTING
) {
944 enqueue_event(session
, PCC_CONNECTION_FAILURE
, NULL
);
946 session
->session_state
= SESSION_STATE_INITIALIZED
;
947 increment_event_counters(session
,
948 PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT
);
952 reset_dead_timer(session
);
954 if (event
->received_msg_list
== NULL
) {
958 /* Message received on socket */
959 double_linked_list_node
*msg_node
;
960 for (msg_node
= event
->received_msg_list
->head
; msg_node
!= NULL
;
961 msg_node
= msg_node
->next_node
) {
962 bool message_enqueued
= false;
963 struct pcep_message
*msg
=
964 (struct pcep_message
*)msg_node
->data
;
965 pcep_log(LOG_INFO
, "%s: \t %s message", __func__
,
966 get_message_type_str(msg
->msg_header
->type
));
968 increment_message_rx_counters(session
, msg
);
970 switch (msg
->msg_header
->type
) {
972 /* handle_pcep_open() checks session state, and for
973 * duplicate erroneous open messages, and replies with
974 * error messages as needed. It also sets
975 * pce_open_received. */
976 if (handle_pcep_open(session
, msg
) == true) {
977 /* PCE Open Message Accepted */
978 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
979 message_enqueued
= true;
980 session
->pce_open_accepted
= true;
981 session
->pce_open_rejected
= false;
982 if (session
->pcc_open_accepted
) {
983 /* If both the PCC and PCE Opens are
984 * accepted, then the session is
987 check_and_send_open_keep_alive(session
);
988 log_pcc_pce_connection(session
);
989 session
->session_state
=
990 SESSION_STATE_PCEP_CONNECTED
;
991 increment_event_counters(
993 PCEP_EVENT_COUNTER_ID_PCE_CONNECT
);
994 enqueue_event(session
,
995 PCC_CONNECTED_TO_PCE
,
1001 case PCEP_TYPE_KEEPALIVE
:
1002 if (session
->session_state
1003 == SESSION_STATE_PCEP_CONNECTING
) {
1004 /* PCC Open Message Accepted */
1005 cancel_timer(session
->timer_id_open_keep_wait
);
1006 session
->timer_id_open_keep_wait
=
1008 session
->pcc_open_accepted
= true;
1009 session
->pcc_open_rejected
= false;
1010 check_and_send_open_keep_alive(session
);
1012 if (session
->pce_open_accepted
) {
1013 /* If both the PCC and PCE Opens are
1014 * accepted, then the session is
1016 log_pcc_pce_connection(session
);
1017 session
->session_state
=
1018 SESSION_STATE_PCEP_CONNECTED
;
1019 increment_event_counters(
1021 PCEP_EVENT_COUNTER_ID_PCC_CONNECT
);
1022 enqueue_event(session
,
1023 PCC_CONNECTED_TO_PCE
,
1027 /* The dead_timer was already reset above, so nothing
1028 * extra to do here */
1031 case PCEP_TYPE_PCREP
:
1032 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1033 message_enqueued
= true;
1036 case PCEP_TYPE_CLOSE
:
1037 session
->session_state
= SESSION_STATE_INITIALIZED
;
1038 socket_comm_session_close_tcp(
1039 session
->socket_comm_session
);
1040 /* TODO should we also enqueue the message, so they can
1041 * see the reasons?? */
1042 enqueue_event(session
, PCE_SENT_PCEP_CLOSE
, NULL
);
1043 /* TODO could this duplicate the disconnect counter with
1044 * socket close ?? */
1045 increment_event_counters(
1046 session
, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT
);
1049 case PCEP_TYPE_PCREQ
:
1050 /* The PCC does not support receiving PcReq messages */
1051 send_pcep_error(session
,
1052 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1053 PCEP_ERRV_UNASSIGNED
);
1056 case PCEP_TYPE_REPORT
:
1057 /* The PCC does not support receiving Report messages */
1058 send_pcep_error(session
,
1059 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1060 PCEP_ERRV_UNASSIGNED
);
1063 case PCEP_TYPE_UPDATE
:
1064 /* Should reply with a PcRpt */
1065 if (handle_pcep_update(session
, msg
) == true) {
1066 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1067 message_enqueued
= true;
1071 case PCEP_TYPE_INITIATE
:
1072 /* Should reply with a PcRpt */
1073 if (handle_pcep_initiate(session
, msg
) == true) {
1074 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1075 message_enqueued
= true;
1079 case PCEP_TYPE_PCNOTF
:
1080 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1081 message_enqueued
= true;
1084 case PCEP_TYPE_ERROR
:
1085 if (msg
->obj_list
!= NULL
1086 && msg
->obj_list
->num_entries
> 0) {
1087 struct pcep_object_header
*obj_hdr
=
1088 pcep_obj_get(msg
->obj_list
,
1089 PCEP_OBJ_CLASS_ERROR
);
1090 if (obj_hdr
!= NULL
) {
1091 struct pcep_object_error
*error_obj
=
1092 (struct pcep_object_error
*)
1096 "%s: Error object [type, value] = [%s, %s]",
1099 error_obj
->error_type
),
1100 get_error_value_str(
1101 error_obj
->error_type
,
1107 if (session
->session_state
1108 == SESSION_STATE_PCEP_CONNECTING
) {
1109 /* A PCC_CONNECTION_FAILURE event will be sent
1110 * when the socket is closed, if the state is
1111 * SESSION_STATE_PCEP_CONNECTING, in case the
1112 * PCE allows more than 2 failed open messages.
1115 "%s: PCC Open message rejected by PCE",
1117 session
->pcc_open_rejected
= true;
1118 send_reconciled_pcep_open(session
, msg
);
1119 enqueue_event(session
, PCC_SENT_INVALID_OPEN
,
1122 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1123 message_enqueued
= true;
1126 case PCEP_TYPE_START_TLS
:
1128 pcep_log(LOG_INFO
, "%s: \t UnSupported message",
1130 send_pcep_error(session
,
1131 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1132 PCEP_ERRV_UNASSIGNED
);
1133 increment_unknown_message(session
);
1137 /* if the message was enqueued, dont free it yet */
1138 if (message_enqueued
== false) {
1139 pcep_msg_free_message(msg
);
1142 dll_destroy(event
->received_msg_list
);