2 * This file is part of the PCEPlib, a PCEP protocol library.
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
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.
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.
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/>.
19 * Author : Brady Johnson <brady@voltanet.io>
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"
40 #define TIMER_OPEN_KEEP_ALIVE_SECONDS 1
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
);
61 * util functions called by the state handling below
64 void send_keep_alive(pcep_session
*session
)
66 struct pcep_message
*keep_alive_msg
= pcep_msg_create_keepalive();
70 "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]",
71 __func__
, time(NULL
), pthread_self(), session
->session_id
);
73 session_send_message(session
, keep_alive_msg
);
75 /* The keep alive timer will be (re)set once the message
76 * is sent in session_logic_message_sent_handler() */
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
)
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
);
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
,
97 session_send_message(session
, error_msg
);
101 void send_pcep_error(pcep_session
*session
, enum pcep_error_type error_type
,
102 enum pcep_error_value error_value
)
104 struct pcep_message
*error_msg
=
105 pcep_msg_create_error(error_type
, error_value
);
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
);
113 session_send_message(session
, error_msg
);
117 void reset_dead_timer(pcep_session
*session
)
119 /* Default to configured dead_timer if its not set yet or set to 0 by
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
;
126 if (session
->timer_id_dead_timer
== TIMER_ID_NOT_SET
) {
127 session
->timer_id_dead_timer
=
128 create_timer(dead_timer_seconds
, session
);
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
);
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
);
147 void enqueue_event(pcep_session
*session
, pcep_event_type event_type
,
148 struct pcep_message
*message
)
150 if (event_type
== MESSAGE_RECEIVED
&& message
== NULL
) {
153 "%s: enqueue_event cannot enqueue a NULL message session [%d]",
154 __func__
, session
->session_id
);
158 pcep_event
*event
= pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_event
));
159 memset(event
, 0, sizeof(pcep_event
));
161 event
->session
= session
;
162 event
->event_type
= event_type
;
163 event
->event_time
= time(NULL
);
164 event
->message
= message
;
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
);
171 queue_enqueue(session_logic_event_queue_
->event_queue
, event
);
173 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
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
)
184 if (open_object
->open_keepalive
185 < session
->pcc_config
.min_keep_alive_seconds
) {
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
;
194 } else if (open_object
->open_keepalive
195 > session
->pcc_config
.max_keep_alive_seconds
) {
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
;
206 if (open_object
->open_deadtimer
207 < session
->pcc_config
.min_dead_timer_seconds
) {
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
;
214 } else if (open_object
->open_deadtimer
215 > session
->pcc_config
.max_dead_timer_seconds
) {
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
;
224 /* Check for Open Object TLVs */
225 if (pcep_object_has_tlvs((struct pcep_object_header
*)open_object
)
227 /* There are no TLVs, all done */
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
;
236 /* Supported Open Object TLVs */
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
:
246 /* TODO how to handle unrecognized TLV ?? */
249 "%s: Unhandled OPEN Object TLV type: %d, length %d",
250 __func__
, tlv
->type
, tlv
->encoded_tlv_length
);
254 /* Verify the STATEFUL-PCE-CAPABILITY TLV */
255 if (tlv
->type
== PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY
) {
256 struct pcep_object_tlv_stateful_pce_capability
259 pcep_object_tlv_stateful_pce_capability
262 /* If the U flag is set, then the PCE is
263 * capable of updating LSP parameters */
264 if (pce_cap_tlv
->flag_u_lsp_update_capability
) {
265 if (session
->pce_config
266 .support_stateful_pce_lsp_update
268 /* Turn off the U bit, as it is not
272 "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
275 ->flag_u_lsp_update_capability
=
279 session
->stateful_pce
= true;
282 "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
283 __func__
, session
->session_id
);
286 /* TODO the rest of the flags are not implemented yet */
287 else if (pce_cap_tlv
->flag_s_include_db_version
) {
290 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
294 ->flag_i_lsp_instantiation_capability
) {
297 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
299 } else if (pce_cap_tlv
->flag_t_triggered_resync
) {
302 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
304 } else if (pce_cap_tlv
->flag_d_delta_lsp_sync
) {
307 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
309 } else if (pce_cap_tlv
->flag_f_triggered_initial_sync
) {
312 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
315 } else if (tlv
->type
== PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
) {
316 if (session
->pce_config
.support_include_db_version
320 "%s: Rejecting unsupported Open LSP DB VERSION TLV",
322 /* Remove this TLV from the list */
323 dll_delete_node(open_object
->header
.tlv_list
,
334 bool handle_pcep_open(pcep_session
*session
, struct pcep_message
*open_msg
)
336 /* Open Message validation and errors according to:
337 * https://tools.ietf.org/html/rfc5440#section-7.15 */
339 if (session
->session_state
!= SESSION_STATE_PCEP_CONNECTING
340 && session
->session_state
!= SESSION_STATE_INITIALIZED
) {
343 "%s: Received unexpected OPEN, current session state [%d, replying with error]",
344 __func__
, session
->session_state
);
345 send_pcep_error(session
,
346 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION
,
347 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
351 if (session
->pce_open_received
== true
352 && session
->pce_open_rejected
== false) {
354 "%s: Received duplicate OPEN, replying with error",
356 send_pcep_error(session
,
357 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION
,
358 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
362 struct pcep_object_open
*open_object
=
363 (struct pcep_object_open
*)pcep_obj_get(open_msg
->obj_list
,
364 PCEP_OBJ_CLASS_OPEN
);
365 if (open_object
== NULL
) {
368 "%s: Received OPEN message with no OPEN object, replying with error",
370 send_pcep_error(session
, PCEP_ERRT_SESSION_FAILURE
,
371 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
375 /* Check for additional Open Msg objects */
376 if (open_msg
->obj_list
->num_entries
> 1) {
379 "%s: Found additional unsupported objects in the Open message, replying with error",
381 send_pcep_error(session
, PCEP_ERRT_SESSION_FAILURE
,
382 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
386 session
->pce_open_received
= true;
388 /* Verify the open object parameters and TLVs */
389 if (verify_pcep_open_object(session
, open_object
) == false) {
390 enqueue_event(session
, PCC_RCVD_INVALID_OPEN
, NULL
);
391 if (session
->pce_open_rejected
) {
392 /* The Open message was already rejected once, so
393 * according to the spec, send an error message and
394 * close the TCP connection. */
397 "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
400 session
, PCEP_ERRT_SESSION_FAILURE
,
401 PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE
);
402 socket_comm_session_close_tcp_after_write(
403 session
->socket_comm_session
);
404 session
->session_state
= SESSION_STATE_INITIALIZED
;
405 enqueue_event(session
, PCC_CONNECTION_FAILURE
, NULL
);
407 session
->pce_open_rejected
= true;
408 /* Clone the object here, since the encapsulating
409 * message will be deleted in handle_socket_comm_event()
410 * most likely before this error message is sent */
411 struct pcep_object_open
*cloned_open_object
=
412 pceplib_malloc(PCEPLIB_MESSAGES
,
413 sizeof(struct pcep_object_open
));
414 memcpy(cloned_open_object
, open_object
,
415 sizeof(struct pcep_object_open
));
416 open_object
->header
.tlv_list
= NULL
;
417 cloned_open_object
->header
.encoded_object
= NULL
;
418 cloned_open_object
->header
.encoded_object_length
= 0;
419 send_pcep_error_with_object(
420 session
, PCEP_ERRT_SESSION_FAILURE
,
421 PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG
,
422 &cloned_open_object
->header
);
429 * Open Message accepted
430 * Sending the keep-alive response will be managed the function caller
433 session
->timer_id_open_keep_alive
=
434 create_timer(TIMER_OPEN_KEEP_ALIVE_SECONDS
, session
);
435 session
->pcc_config
.dead_timer_pce_negotiated_seconds
=
436 (int)open_object
->open_deadtimer
;
437 /* Cancel the timer so we can change the dead_timer value */
438 cancel_timer(session
->timer_id_dead_timer
);
439 session
->timer_id_dead_timer
= TIMER_ID_NOT_SET
;
440 reset_dead_timer(session
);
446 /* The original PCEP Open message sent to the PCE was rejected,
447 * try to reconcile the differences and re-send a new Open. */
448 void send_reconciled_pcep_open(pcep_session
*session
,
449 struct pcep_message
*error_msg
)
451 struct pcep_message
*open_msg
= create_pcep_open(session
);
453 struct pcep_object_open
*error_open_obj
=
454 (struct pcep_object_open
*)pcep_obj_get(error_msg
->obj_list
,
455 PCEP_OBJ_CLASS_OPEN
);
456 if (error_open_obj
== NULL
) {
457 /* Nothing to reconcile, send the same Open message again */
460 "%s: No Open object received in Error, sending the same Open message",
462 session_send_message(session
, open_msg
);
466 struct pcep_object_open
*open_obj
=
467 (struct pcep_object_open
*)pcep_obj_get(open_msg
->obj_list
,
468 PCEP_OBJ_CLASS_OPEN
);
469 // open_msg can not have empty obj_list
470 assert(open_obj
!= NULL
);
472 if (error_open_obj
->open_deadtimer
473 != session
->pce_config
.dead_timer_seconds
) {
474 if (error_open_obj
->open_deadtimer
475 >= session
->pce_config
.min_dead_timer_seconds
476 && error_open_obj
->open_deadtimer
477 <= session
->pce_config
.max_dead_timer_seconds
) {
478 open_obj
->open_deadtimer
=
479 error_open_obj
->open_deadtimer
;
480 session
->pcc_config
.dead_timer_pce_negotiated_seconds
=
481 error_open_obj
->open_deadtimer
;
484 "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
486 session
->pcc_config
.dead_timer_seconds
,
488 .dead_timer_pce_negotiated_seconds
);
489 /* Reset the timer with the new value */
490 cancel_timer(session
->timer_id_dead_timer
);
491 session
->timer_id_dead_timer
= TIMER_ID_NOT_SET
;
492 reset_dead_timer(session
);
496 "%s: Can not reconcile Open with suggested deadtimer [%d]",
497 __func__
, error_open_obj
->open_deadtimer
);
501 if (error_open_obj
->open_keepalive
502 != session
->pce_config
.keep_alive_seconds
) {
503 if (error_open_obj
->open_keepalive
504 >= session
->pce_config
.min_keep_alive_seconds
505 && error_open_obj
->open_keepalive
506 <= session
->pce_config
.max_keep_alive_seconds
) {
507 open_obj
->open_keepalive
=
508 error_open_obj
->open_keepalive
;
510 .keep_alive_pce_negotiated_timer_seconds
=
511 error_open_obj
->open_keepalive
;
514 "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
516 session
->pcc_config
.keep_alive_seconds
,
518 .keep_alive_pce_negotiated_timer_seconds
);
519 /* Cancel the timer, the timer will be set again with
520 * the new value when this open message is sent */
521 cancel_timer(session
->timer_id_keep_alive
);
522 session
->timer_id_keep_alive
= TIMER_ID_NOT_SET
;
526 "%s: Can not reconcile Open with suggested keepalive [%d]",
527 __func__
, error_open_obj
->open_keepalive
);
531 /* TODO reconcile the TLVs */
533 session_send_message(session
, open_msg
);
534 reset_timer(session
->timer_id_open_keep_alive
);
538 bool handle_pcep_update(pcep_session
*session
, struct pcep_message
*upd_msg
)
540 /* Update Message validation and errors according to:
541 * https://tools.ietf.org/html/rfc8231#section-6.2 */
543 if (upd_msg
->obj_list
== NULL
) {
545 "%s: Invalid PcUpd message: Message has no objects",
547 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
548 PCEP_ERRV_SRP_OBJECT_MISSING
);
552 /* Verify the mandatory objects are present */
553 struct pcep_object_header
*obj
=
554 pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_SRP
);
557 "%s: Invalid PcUpd message: Missing SRP object",
559 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
560 PCEP_ERRV_SRP_OBJECT_MISSING
);
564 obj
= pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_LSP
);
567 "%s: Invalid PcUpd message: Missing LSP object",
569 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
570 PCEP_ERRV_LSP_OBJECT_MISSING
);
574 obj
= pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_ERO
);
577 "%s: Invalid PcUpd message: Missing ERO object",
579 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
580 PCEP_ERRV_ERO_OBJECT_MISSING
);
584 /* Verify the objects are are in the correct order */
585 double_linked_list_node
*node
= upd_msg
->obj_list
->head
;
586 struct pcep_object_srp
*srp_object
=
587 (struct pcep_object_srp
*)node
->data
;
588 if (srp_object
->header
.object_class
!= PCEP_OBJ_CLASS_SRP
) {
591 "%s: Invalid PcUpd message: First object must be an SRP, found [%d]",
592 __func__
, srp_object
->header
.object_class
);
593 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
594 PCEP_ERRV_SRP_OBJECT_MISSING
);
598 node
= node
->next_node
;
599 struct pcep_object_lsp
*lsp_object
=
600 (struct pcep_object_lsp
*)node
->data
;
601 if (lsp_object
->header
.object_class
!= PCEP_OBJ_CLASS_LSP
) {
604 "%s: Invalid PcUpd message: Second object must be an LSP, found [%d]",
605 __func__
, lsp_object
->header
.object_class
);
606 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
607 PCEP_ERRV_LSP_OBJECT_MISSING
);
611 node
= node
->next_node
;
612 struct pcep_object_ro
*ero_object
= node
->data
;
613 if (ero_object
->header
.object_class
!= PCEP_OBJ_CLASS_ERO
) {
616 "%s: Invalid PcUpd message: Third object must be an ERO, found [%d]",
617 __func__
, ero_object
->header
.object_class
);
618 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
619 PCEP_ERRV_ERO_OBJECT_MISSING
);
626 bool handle_pcep_initiate(pcep_session
*session
, struct pcep_message
*init_msg
)
628 /* Instantiate Message validation and errors according to:
629 * https://tools.ietf.org/html/rfc8281#section-5 */
631 if (init_msg
->obj_list
== NULL
) {
634 "%s: Invalid PcInitiate message: Message has no objects",
636 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
637 PCEP_ERRV_SRP_OBJECT_MISSING
);
641 /* Verify the mandatory objects are present */
642 struct pcep_object_header
*obj
=
643 pcep_obj_get(init_msg
->obj_list
, PCEP_OBJ_CLASS_SRP
);
646 "%s: Invalid PcInitiate message: Missing SRP object",
648 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
649 PCEP_ERRV_SRP_OBJECT_MISSING
);
653 obj
= pcep_obj_get(init_msg
->obj_list
, PCEP_OBJ_CLASS_LSP
);
656 "%s: Invalid PcInitiate message: Missing LSP object",
658 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
659 PCEP_ERRV_LSP_OBJECT_MISSING
);
663 /* Verify the objects are are in the correct order */
664 double_linked_list_node
*node
= init_msg
->obj_list
->head
;
665 struct pcep_object_srp
*srp_object
=
666 (struct pcep_object_srp
*)node
->data
;
667 if (srp_object
->header
.object_class
!= PCEP_OBJ_CLASS_SRP
) {
670 "%s: Invalid PcInitiate message: First object must be an SRP, found [%d]",
671 __func__
, srp_object
->header
.object_class
);
672 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
673 PCEP_ERRV_SRP_OBJECT_MISSING
);
677 node
= node
->next_node
;
678 struct pcep_object_lsp
*lsp_object
=
679 (struct pcep_object_lsp
*)node
->data
;
680 if (lsp_object
->header
.object_class
!= PCEP_OBJ_CLASS_LSP
) {
683 "%s: Invalid PcInitiate message: Second object must be an LSP, found [%d]",
684 __func__
, lsp_object
->header
.object_class
);
685 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
686 PCEP_ERRV_LSP_OBJECT_MISSING
);
690 /* There may be more optional objects */
694 void increment_unknown_message(pcep_session
*session
)
696 /* https://tools.ietf.org/html/rfc5440#section-6.9
697 * If a PCC/PCE receives unrecognized messages at a rate equal or
698 * greater than MAX-UNKNOWN-MESSAGES unknown message requests per
699 * minute, the PCC/PCE MUST send a PCEP CLOSE message */
701 time_t *unknown_message_time
=
702 pceplib_malloc(PCEPLIB_INFRA
, sizeof(time_t));
703 *unknown_message_time
= time(NULL
);
704 time_t expire_time
= *unknown_message_time
+ 60;
705 queue_enqueue(session
->num_unknown_messages_time_queue
,
706 unknown_message_time
);
708 /* Purge any entries older than 1 minute. The oldest entries are at the
710 queue_node
*time_node
= session
->num_unknown_messages_time_queue
->head
;
711 while (time_node
!= NULL
) {
712 if (*((time_t *)time_node
->data
) > expire_time
) {
716 session
->num_unknown_messages_time_queue
));
718 session
->num_unknown_messages_time_queue
->head
;
724 if ((int)session
->num_unknown_messages_time_queue
->num_entries
725 >= session
->pcc_config
.max_unknown_messages
) {
728 "%s: [%ld-%ld] Max unknown messages reached [%d] closing session [%d]",
729 __func__
, time(NULL
), pthread_self(),
730 session
->pcc_config
.max_unknown_messages
,
731 session
->session_id
);
733 close_pcep_session_with_reason(session
,
734 PCEP_CLOSE_REASON_UNREC_MSG
);
735 enqueue_event(session
, PCC_RCVD_MAX_UNKOWN_MSGS
, NULL
);
739 bool check_and_send_open_keep_alive(pcep_session
*session
)
741 if (session
->pce_open_received
== true
742 && session
->pce_open_rejected
== false
743 && session
->pce_open_keep_alive_sent
== false) {
744 /* Send the PCE Open keep-alive response if it hasnt been sent
746 cancel_timer(session
->timer_id_open_keep_alive
);
747 session
->timer_id_open_keep_alive
= TIMER_ID_NOT_SET
;
748 send_keep_alive(session
);
749 session
->pce_open_keep_alive_sent
= true;
757 void log_pcc_pce_connection(pcep_session
*session
)
759 if (session
->socket_comm_session
== NULL
) {
760 /* This only happens in UT */
764 char src_ip_buf
[40] = {0}, dst_ip_buf
[40] = {0};
765 uint16_t src_port
, dst_port
;
767 if (session
->socket_comm_session
->is_ipv6
) {
769 &session
->socket_comm_session
->src_sock_addr
770 .src_sock_addr_ipv6
.sin6_addr
,
771 src_ip_buf
, sizeof(src_ip_buf
));
773 &session
->socket_comm_session
->dest_sock_addr
774 .dest_sock_addr_ipv6
.sin6_addr
,
775 dst_ip_buf
, sizeof(dst_ip_buf
));
776 src_port
= htons(session
->socket_comm_session
->src_sock_addr
777 .src_sock_addr_ipv6
.sin6_port
);
778 dst_port
= htons(session
->socket_comm_session
->dest_sock_addr
779 .dest_sock_addr_ipv6
.sin6_port
);
782 &session
->socket_comm_session
->src_sock_addr
783 .src_sock_addr_ipv4
.sin_addr
,
784 src_ip_buf
, sizeof(src_ip_buf
));
786 &session
->socket_comm_session
->dest_sock_addr
787 .dest_sock_addr_ipv4
.sin_addr
,
788 dst_ip_buf
, sizeof(dst_ip_buf
));
789 src_port
= htons(session
->socket_comm_session
->src_sock_addr
790 .src_sock_addr_ipv4
.sin_port
);
791 dst_port
= htons(session
->socket_comm_session
->dest_sock_addr
792 .dest_sock_addr_ipv4
.sin_port
);
797 "%s: [%ld-%ld] Successful PCC [%s:%d] connection to PCE [%s:%d] session [%d] fd [%d]",
798 __func__
, time(NULL
), pthread_self(), src_ip_buf
, src_port
,
799 dst_ip_buf
, dst_port
, session
->session_id
,
800 session
->socket_comm_session
->socket_fd
);
804 * these functions are called by session_logic_loop() from
805 * pcep_session_logic_loop.c these functions are executed in the
806 * session_logic_loop thread, and the mutex is locked before calling these
807 * functions, so they are thread safe.
810 /* state machine handling for expired timers */
811 void handle_timer_event(pcep_session_event
*event
)
814 pcep_log(LOG_INFO
, "%s: handle_timer_event NULL event",
819 pcep_session
*session
= event
->session
;
823 "%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]",
824 __func__
, time(NULL
), pthread_self(), session
->session_id
,
825 event
->expired_timer_id
, session
->timer_id_open_keep_wait
,
826 session
->timer_id_open_keep_alive
, session
->timer_id_dead_timer
,
827 session
->timer_id_keep_alive
);
830 * these timer expirations are independent of the session state
832 if (event
->expired_timer_id
== session
->timer_id_dead_timer
) {
833 session
->timer_id_dead_timer
= TIMER_ID_NOT_SET
;
834 increment_event_counters(session
,
835 PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER
);
836 close_pcep_session_with_reason(session
,
837 PCEP_CLOSE_REASON_DEADTIMER
);
838 enqueue_event(session
, PCE_DEAD_TIMER_EXPIRED
, NULL
);
840 } else if (event
->expired_timer_id
== session
->timer_id_keep_alive
) {
841 session
->timer_id_keep_alive
= TIMER_ID_NOT_SET
;
842 increment_event_counters(session
,
843 PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE
);
844 send_keep_alive(session
);
849 * handle timers that depend on the session state
851 switch (session
->session_state
) {
852 case SESSION_STATE_PCEP_CONNECTING
:
853 if (event
->expired_timer_id
854 == session
->timer_id_open_keep_wait
) {
855 /* close the TCP session */
858 "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
859 __func__
, session
->session_id
);
860 increment_event_counters(
862 PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT
);
863 socket_comm_session_close_tcp_after_write(
864 session
->socket_comm_session
);
865 session
->session_state
= SESSION_STATE_INITIALIZED
;
866 session
->timer_id_open_keep_wait
= TIMER_ID_NOT_SET
;
867 enqueue_event(session
, PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED
,
871 if (event
->expired_timer_id
872 == session
->timer_id_open_keep_alive
) {
873 increment_event_counters(
875 PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE
);
876 session
->timer_id_open_keep_alive
= TIMER_ID_NOT_SET
;
877 if (check_and_send_open_keep_alive(session
) == true) {
878 if (session
->pcc_open_accepted
== true
879 && session
->session_state
880 != SESSION_STATE_PCEP_CONNECTED
) {
881 log_pcc_pce_connection(session
);
882 session
->session_state
=
883 SESSION_STATE_PCEP_CONNECTED
;
884 increment_event_counters(
886 PCEP_EVENT_COUNTER_ID_PCE_CONNECT
);
887 enqueue_event(session
,
888 PCC_CONNECTED_TO_PCE
,
896 case SESSION_STATE_INITIALIZED
:
897 case SESSION_STATE_PCEP_CONNECTED
:
901 "%s: handle_timer_event unrecognized state transition, timer_id [%d] state [%d] session [%d]",
902 __func__
, event
->expired_timer_id
,
903 session
->session_state
, session
->session_id
);
908 /* State machine handling for received messages.
909 * This event was created in session_logic_msg_ready_handler() in
910 * pcep_session_logic_loop.c */
911 void handle_socket_comm_event(pcep_session_event
*event
)
914 pcep_log(LOG_INFO
, "%s: handle_socket_comm_event NULL event",
919 pcep_session
*session
= event
->session
;
923 "%s: [%ld-%ld] pcep_session_logic handle_socket_comm_event: session [%d] num messages [%d] socket_closed [%d]",
924 __func__
, time(NULL
), pthread_self(), session
->session_id
,
925 (event
->received_msg_list
== NULL
927 : (int)event
->received_msg_list
->num_entries
),
928 event
->socket_closed
);
931 * independent of the session state
933 if (event
->socket_closed
) {
936 "%s: handle_socket_comm_event socket closed for session [%d]",
937 __func__
, session
->session_id
);
938 socket_comm_session_close_tcp(session
->socket_comm_session
);
939 enqueue_event(session
, PCE_CLOSED_SOCKET
, NULL
);
940 if (session
->session_state
== SESSION_STATE_PCEP_CONNECTING
) {
941 enqueue_event(session
, PCC_CONNECTION_FAILURE
, NULL
);
943 session
->session_state
= SESSION_STATE_INITIALIZED
;
944 increment_event_counters(session
,
945 PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT
);
949 reset_dead_timer(session
);
951 if (event
->received_msg_list
== NULL
) {
955 /* Message received on socket */
956 double_linked_list_node
*msg_node
;
957 for (msg_node
= event
->received_msg_list
->head
; msg_node
!= NULL
;
958 msg_node
= msg_node
->next_node
) {
959 bool message_enqueued
= false;
960 struct pcep_message
*msg
=
961 (struct pcep_message
*)msg_node
->data
;
962 pcep_log(LOG_INFO
, "%s: \t %s message", __func__
,
963 get_message_type_str(msg
->msg_header
->type
));
965 increment_message_rx_counters(session
, msg
);
967 switch (msg
->msg_header
->type
) {
969 /* handle_pcep_open() checks session state, and for
970 * duplicate erroneous open messages, and replies with
971 * error messages as needed. It also sets
972 * pce_open_received. */
973 if (handle_pcep_open(session
, msg
) == true) {
974 /* PCE Open Message Accepted */
975 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
976 message_enqueued
= true;
977 session
->pce_open_accepted
= true;
978 session
->pce_open_rejected
= false;
979 if (session
->pcc_open_accepted
) {
980 /* If both the PCC and PCE Opens are
981 * accepted, then the session is
984 check_and_send_open_keep_alive(session
);
985 log_pcc_pce_connection(session
);
986 session
->session_state
=
987 SESSION_STATE_PCEP_CONNECTED
;
988 increment_event_counters(
990 PCEP_EVENT_COUNTER_ID_PCE_CONNECT
);
991 enqueue_event(session
,
992 PCC_CONNECTED_TO_PCE
,
998 case PCEP_TYPE_KEEPALIVE
:
999 if (session
->session_state
1000 == SESSION_STATE_PCEP_CONNECTING
) {
1001 /* PCC Open Message Accepted */
1002 cancel_timer(session
->timer_id_open_keep_wait
);
1003 session
->timer_id_open_keep_wait
=
1005 session
->pcc_open_accepted
= true;
1006 session
->pcc_open_rejected
= false;
1007 check_and_send_open_keep_alive(session
);
1009 if (session
->pce_open_accepted
) {
1010 /* If both the PCC and PCE Opens are
1011 * accepted, then the session is
1013 log_pcc_pce_connection(session
);
1014 session
->session_state
=
1015 SESSION_STATE_PCEP_CONNECTED
;
1016 increment_event_counters(
1018 PCEP_EVENT_COUNTER_ID_PCC_CONNECT
);
1019 enqueue_event(session
,
1020 PCC_CONNECTED_TO_PCE
,
1024 /* The dead_timer was already reset above, so nothing
1025 * extra to do here */
1028 case PCEP_TYPE_PCREP
:
1029 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1030 message_enqueued
= true;
1033 case PCEP_TYPE_CLOSE
:
1034 session
->session_state
= SESSION_STATE_INITIALIZED
;
1035 socket_comm_session_close_tcp(
1036 session
->socket_comm_session
);
1037 /* TODO should we also enqueue the message, so they can
1038 * see the reasons?? */
1039 enqueue_event(session
, PCE_SENT_PCEP_CLOSE
, NULL
);
1040 /* TODO could this duplicate the disconnect counter with
1041 * socket close ?? */
1042 increment_event_counters(
1043 session
, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT
);
1046 case PCEP_TYPE_PCREQ
:
1047 /* The PCC does not support receiving PcReq messages */
1048 send_pcep_error(session
,
1049 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1050 PCEP_ERRV_UNASSIGNED
);
1053 case PCEP_TYPE_REPORT
:
1054 /* The PCC does not support receiving Report messages */
1055 send_pcep_error(session
,
1056 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1057 PCEP_ERRV_UNASSIGNED
);
1060 case PCEP_TYPE_UPDATE
:
1061 /* Should reply with a PcRpt */
1062 if (handle_pcep_update(session
, msg
) == true) {
1063 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1064 message_enqueued
= true;
1068 case PCEP_TYPE_INITIATE
:
1069 /* Should reply with a PcRpt */
1070 if (handle_pcep_initiate(session
, msg
) == true) {
1071 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1072 message_enqueued
= true;
1076 case PCEP_TYPE_PCNOTF
:
1077 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1078 message_enqueued
= true;
1081 case PCEP_TYPE_ERROR
:
1082 if (msg
->obj_list
!= NULL
1083 && msg
->obj_list
->num_entries
> 0) {
1084 struct pcep_object_header
*obj_hdr
=
1085 pcep_obj_get(msg
->obj_list
,
1086 PCEP_OBJ_CLASS_ERROR
);
1087 if (obj_hdr
!= NULL
) {
1088 struct pcep_object_error
*error_obj
=
1089 (struct pcep_object_error
*)
1093 "%s: Error object [type, value] = [%s, %s]",
1096 error_obj
->error_type
),
1097 get_error_value_str(
1098 error_obj
->error_type
,
1104 if (session
->session_state
1105 == SESSION_STATE_PCEP_CONNECTING
) {
1106 /* A PCC_CONNECTION_FAILURE event will be sent
1107 * when the socket is closed, if the state is
1108 * SESSION_STATE_PCEP_CONNECTING, in case the
1109 * PCE allows more than 2 failed open messages.
1112 "%s: PCC Open message rejected by PCE",
1114 session
->pcc_open_rejected
= true;
1115 send_reconciled_pcep_open(session
, msg
);
1116 enqueue_event(session
, PCC_SENT_INVALID_OPEN
,
1119 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1120 message_enqueued
= true;
1124 pcep_log(LOG_INFO
, "%s: \t UnSupported message",
1126 send_pcep_error(session
,
1127 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1128 PCEP_ERRV_UNASSIGNED
);
1129 increment_unknown_message(session
);
1133 /* if the message was enqueued, dont free it yet */
1134 if (message_enqueued
== false) {
1135 pcep_msg_free_message(msg
);
1138 dll_destroy(event
->received_msg_list
);