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
:
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 ?? */
264 "%s: Unhandled OPEN Object TLV type: %d, length %d",
265 __func__
, tlv
->type
, tlv
->encoded_tlv_length
);
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
274 pcep_object_tlv_stateful_pce_capability
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
283 /* Turn off the U bit, as it is not
287 "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
290 ->flag_u_lsp_update_capability
=
294 session
->stateful_pce
= true;
297 "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
298 __func__
, session
->session_id
);
301 /* TODO the rest of the flags are not implemented yet */
302 else if (pce_cap_tlv
->flag_s_include_db_version
) {
305 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
309 ->flag_i_lsp_instantiation_capability
) {
312 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
314 } else if (pce_cap_tlv
->flag_t_triggered_resync
) {
317 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
319 } else if (pce_cap_tlv
->flag_d_delta_lsp_sync
) {
322 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
324 } else if (pce_cap_tlv
->flag_f_triggered_initial_sync
) {
327 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
330 } else if (tlv
->type
== PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION
) {
331 if (session
->pce_config
.support_include_db_version
335 "%s: Rejecting unsupported Open LSP DB VERSION TLV",
337 /* Remove this TLV from the list */
338 dll_delete_node(open_object
->header
.tlv_list
,
349 bool handle_pcep_open(pcep_session
*session
, struct pcep_message
*open_msg
)
351 /* Open Message validation and errors according to:
352 * https://tools.ietf.org/html/rfc5440#section-7.15 */
354 if (session
->session_state
!= SESSION_STATE_PCEP_CONNECTING
355 && session
->session_state
!= SESSION_STATE_INITIALIZED
) {
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
);
366 if (session
->pce_open_received
== true
367 && session
->pce_open_rejected
== false) {
369 "%s: Received duplicate OPEN, replying with error",
371 send_pcep_error(session
,
372 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION
,
373 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
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
) {
383 "%s: Received OPEN message with no OPEN object, replying with error",
385 send_pcep_error(session
, PCEP_ERRT_SESSION_FAILURE
,
386 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
390 /* Check for additional Open Msg objects */
391 if (open_msg
->obj_list
->num_entries
> 1) {
394 "%s: Found additional unsupported objects in the Open message, replying with error",
396 send_pcep_error(session
, PCEP_ERRT_SESSION_FAILURE
,
397 PCEP_ERRV_RECVD_INVALID_OPEN_MSG
);
401 session
->pce_open_received
= true;
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. */
412 "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
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
);
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
);
444 * Open Message accepted
445 * Sending the keep-alive response will be managed the function caller
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
);
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
)
466 struct pcep_message
*open_msg
= create_pcep_open(session
);
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 */
475 "%s: No Open object received in Error, sending the same Open message",
477 session_send_message(session
, open_msg
);
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
);
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
;
499 "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
501 session
->pcc_config
.dead_timer_seconds
,
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
);
511 "%s: Can not reconcile Open with suggested deadtimer [%d]",
512 __func__
, error_open_obj
->open_deadtimer
);
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
;
525 .keep_alive_pce_negotiated_timer_seconds
=
526 error_open_obj
->open_keepalive
;
529 "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
531 session
->pcc_config
.keep_alive_seconds
,
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
;
541 "%s: Can not reconcile Open with suggested keepalive [%d]",
542 __func__
, error_open_obj
->open_keepalive
);
546 /* TODO reconcile the TLVs */
548 session_send_message(session
, open_msg
);
549 reset_timer(session
->timer_id_open_keep_alive
);
553 bool handle_pcep_update(pcep_session
*session
, struct pcep_message
*upd_msg
)
555 /* Update Message validation and errors according to:
556 * https://tools.ietf.org/html/rfc8231#section-6.2 */
558 if (upd_msg
->obj_list
== NULL
) {
560 "%s: Invalid PcUpd message: Message has no objects",
562 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
563 PCEP_ERRV_SRP_OBJECT_MISSING
);
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
);
572 "%s: Invalid PcUpd message: Missing SRP object",
574 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
575 PCEP_ERRV_SRP_OBJECT_MISSING
);
579 obj
= pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_LSP
);
582 "%s: Invalid PcUpd message: Missing LSP object",
584 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
585 PCEP_ERRV_LSP_OBJECT_MISSING
);
589 obj
= pcep_obj_get(upd_msg
->obj_list
, PCEP_OBJ_CLASS_ERO
);
592 "%s: Invalid PcUpd message: Missing ERO object",
594 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
595 PCEP_ERRV_ERO_OBJECT_MISSING
);
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
) {
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
);
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
) {
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
);
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
) {
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
);
641 bool handle_pcep_initiate(pcep_session
*session
, struct pcep_message
*init_msg
)
643 /* Instantiate Message validation and errors according to:
644 * https://tools.ietf.org/html/rfc8281#section-5 */
646 if (init_msg
->obj_list
== NULL
) {
649 "%s: Invalid PcInitiate message: Message has no objects",
651 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
652 PCEP_ERRV_SRP_OBJECT_MISSING
);
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
);
661 "%s: Invalid PcInitiate message: Missing SRP object",
663 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
664 PCEP_ERRV_SRP_OBJECT_MISSING
);
668 obj
= pcep_obj_get(init_msg
->obj_list
, PCEP_OBJ_CLASS_LSP
);
671 "%s: Invalid PcInitiate message: Missing LSP object",
673 send_pcep_error(session
, PCEP_ERRT_MANDATORY_OBJECT_MISSING
,
674 PCEP_ERRV_LSP_OBJECT_MISSING
);
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
) {
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
);
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
) {
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
);
705 /* There may be more optional objects */
709 void increment_unknown_message(pcep_session
*session
)
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 */
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
);
723 /* Purge any entries older than 1 minute. The oldest entries are at the
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
) {
731 session
->num_unknown_messages_time_queue
));
733 session
->num_unknown_messages_time_queue
->head
;
739 if ((int)session
->num_unknown_messages_time_queue
->num_entries
740 >= session
->pcc_config
.max_unknown_messages
) {
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
);
748 close_pcep_session_with_reason(session
,
749 PCEP_CLOSE_REASON_UNREC_MSG
);
750 enqueue_event(session
, PCC_RCVD_MAX_UNKOWN_MSGS
, NULL
);
754 bool check_and_send_open_keep_alive(pcep_session
*session
)
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
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;
772 void log_pcc_pce_connection(pcep_session
*session
)
774 if (session
->socket_comm_session
== NULL
) {
775 /* This only happens in UT */
779 char src_ip_buf
[40] = {0}, dst_ip_buf
[40] = {0};
780 uint16_t src_port
, dst_port
;
782 if (session
->socket_comm_session
->is_ipv6
) {
784 &session
->socket_comm_session
->src_sock_addr
785 .src_sock_addr_ipv6
.sin6_addr
,
786 src_ip_buf
, sizeof(src_ip_buf
));
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
);
797 &session
->socket_comm_session
->src_sock_addr
798 .src_sock_addr_ipv4
.sin_addr
,
799 src_ip_buf
, sizeof(src_ip_buf
));
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
);
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
);
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.
825 /* state machine handling for expired timers */
826 void handle_timer_event(pcep_session_event
*event
)
829 pcep_log(LOG_INFO
, "%s: handle_timer_event NULL event",
834 pcep_session
*session
= event
->session
;
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
);
845 * these timer expirations are independent of the session state
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
);
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
);
864 * handle timers that depend on the session state
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 */
873 "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
874 __func__
, session
->session_id
);
875 increment_event_counters(
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
,
886 if (event
->expired_timer_id
887 == session
->timer_id_open_keep_alive
) {
888 increment_event_counters(
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(
901 PCEP_EVENT_COUNTER_ID_PCE_CONNECT
);
902 enqueue_event(session
,
903 PCC_CONNECTED_TO_PCE
,
911 case SESSION_STATE_INITIALIZED
:
912 case SESSION_STATE_PCEP_CONNECTED
:
913 case SESSION_STATE_UNKNOWN
:
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
);
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
)
929 pcep_log(LOG_INFO
, "%s: handle_socket_comm_event NULL event",
934 pcep_session
*session
= event
->session
;
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
942 : (int)event
->received_msg_list
->num_entries
),
943 event
->socket_closed
);
946 * independent of the session state
948 if (event
->socket_closed
) {
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
);
958 session
->session_state
= SESSION_STATE_INITIALIZED
;
959 increment_event_counters(session
,
960 PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT
);
964 reset_dead_timer(session
);
966 if (event
->received_msg_list
== NULL
) {
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
));
980 increment_message_rx_counters(session
, msg
);
982 switch (msg
->msg_header
->type
) {
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
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(
1005 PCEP_EVENT_COUNTER_ID_PCE_CONNECT
);
1006 enqueue_event(session
,
1007 PCC_CONNECTED_TO_PCE
,
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
=
1020 session
->pcc_open_accepted
= true;
1021 session
->pcc_open_rejected
= false;
1022 check_and_send_open_keep_alive(session
);
1024 if (session
->pce_open_accepted
) {
1025 /* If both the PCC and PCE Opens are
1026 * accepted, then the session is
1028 log_pcc_pce_connection(session
);
1029 session
->session_state
=
1030 SESSION_STATE_PCEP_CONNECTED
;
1031 increment_event_counters(
1033 PCEP_EVENT_COUNTER_ID_PCC_CONNECT
);
1034 enqueue_event(session
,
1035 PCC_CONNECTED_TO_PCE
,
1039 /* The dead_timer was already reset above, so nothing
1040 * extra to do here */
1043 case PCEP_TYPE_PCREP
:
1044 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1045 message_enqueued
= true;
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
);
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
);
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
);
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;
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;
1091 case PCEP_TYPE_PCNOTF
:
1092 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1093 message_enqueued
= true;
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
*)
1108 "%s: Error object [type, value] = [%s, %s]",
1111 error_obj
->error_type
),
1112 get_error_value_str(
1113 error_obj
->error_type
,
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.
1127 "%s: PCC Open message rejected by PCE",
1129 session
->pcc_open_rejected
= true;
1130 send_reconciled_pcep_open(session
, msg
);
1131 enqueue_event(session
, PCC_SENT_INVALID_OPEN
,
1134 enqueue_event(session
, MESSAGE_RECEIVED
, msg
);
1135 message_enqueued
= true;
1138 case PCEP_TYPE_START_TLS
:
1140 pcep_log(LOG_INFO
, "%s: \t UnSupported message",
1142 send_pcep_error(session
,
1143 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED
,
1144 PCEP_ERRV_UNASSIGNED
);
1145 increment_unknown_message(session
);
1149 /* if the message was enqueued, dont free it yet */
1150 if (message_enqueued
== false) {
1151 pcep_msg_free_message(msg
);
1154 dll_destroy(event
->received_msg_list
);