]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_session_logic_states.c
Merge pull request #12159 from opensourcerouting/fix/conditional_advertisement_track_...
[mirror_frr.git] / pceplib / pcep_session_logic_states.c
CommitLineData
74971473
JG
1/*
2 * This file is part of the PCEPlib, a PCEP protocol library.
3 *
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 *
19 * Author : Brady Johnson <brady@voltanet.io>
20 *
21 */
22
1f8031f7
DL
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
74971473
JG
27#include <pthread.h>
28#include <stdbool.h>
29#include <stdio.h>
30#include <string.h>
7ed8c4b1 31#include <assert.h>
74971473
JG
32
33#include "pcep_msg_encoding.h"
34#include "pcep_session_logic.h"
35#include "pcep_session_logic_internals.h"
36#include "pcep_timers.h"
37#include "pcep_utils_logging.h"
38#include "pcep_utils_memory.h"
39
40#define TIMER_OPEN_KEEP_ALIVE_SECONDS 1
41
42/* Session Logic Handle managed in pcep_session_logic.c */
43extern pcep_event_queue *session_logic_event_queue_;
44void send_keep_alive(pcep_session *session);
45void 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);
49void reset_dead_timer(pcep_session *session);
50bool verify_pcep_open_object(pcep_session *session,
51 struct pcep_object_open *open_object);
52void send_reconciled_pcep_open(pcep_session *session,
53 struct pcep_message *error_msg);
54bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg);
55bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg);
56bool check_and_send_open_keep_alive(pcep_session *session);
57void log_pcc_pce_connection(pcep_session *session);
58bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg);
59
60/*
61 * util functions called by the state handling below
62 */
63
64void send_keep_alive(pcep_session *session)
65{
66 struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive();
67
68 pcep_log(
69 LOG_INFO,
70 "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]",
71 __func__, time(NULL), pthread_self(), session->session_id);
72
73 session_send_message(session, keep_alive_msg);
74
75 /* The keep alive timer will be (re)set once the message
76 * is sent in session_logic_message_sent_handler() */
77}
78
79
80/* Send an error message with the corrected or offending object */
81void send_pcep_error_with_object(pcep_session *session,
82 enum pcep_error_type error_type,
83 enum pcep_error_value error_value,
84 struct pcep_object_header *object)
85{
86 double_linked_list *obj_list = dll_initialize();
87 dll_append(obj_list, object);
88 struct pcep_message *error_msg = pcep_msg_create_error_with_objects(
89 error_type, error_value, obj_list);
90
91 pcep_log(
92 LOG_INFO,
93 "%s: [%ld-%ld] pcep_session_logic send error message with object [%d][%d] for session [%d]",
94 __func__, time(NULL), pthread_self(), error_type, error_value,
95 session->session_id);
96
97 session_send_message(session, error_msg);
98}
99
100
101void send_pcep_error(pcep_session *session, enum pcep_error_type error_type,
102 enum pcep_error_value error_value)
103{
104 struct pcep_message *error_msg =
105 pcep_msg_create_error(error_type, error_value);
106
107 pcep_log(
108 LOG_INFO,
109 "%s: [%ld-%ld] pcep_session_logic send error message [%d][%d] for session [%d]",
110 __func__, time(NULL), pthread_self(), error_type, error_value,
111 session->session_id);
112
113 session_send_message(session, error_msg);
114}
115
116
117void reset_dead_timer(pcep_session *session)
118{
119 /* Default to configured dead_timer if its not set yet or set to 0 by
120 * the PCE */
121 int dead_timer_seconds =
122 (session->pcc_config.dead_timer_pce_negotiated_seconds == 0)
123 ? session->pcc_config.dead_timer_seconds
124 : session->pcc_config.dead_timer_pce_negotiated_seconds;
125
126 if (session->timer_id_dead_timer == TIMER_ID_NOT_SET) {
127 session->timer_id_dead_timer =
128 create_timer(dead_timer_seconds, session);
129 pcep_log(
130 LOG_INFO,
131 "%s: [%ld-%ld] pcep_session_logic set dead timer [%d secs] id [%d] for session [%d]",
132 __func__, time(NULL), pthread_self(),
133 dead_timer_seconds, session->timer_id_dead_timer,
134 session->session_id);
135 } else {
136 pcep_log(
137 LOG_INFO,
138 "%s: [%ld-%ld] pcep_session_logic reset dead timer [%d secs] id [%d] for session [%d]",
139 __func__, time(NULL), pthread_self(),
140 dead_timer_seconds, session->timer_id_dead_timer,
141 session->session_id);
142 reset_timer(session->timer_id_dead_timer);
143 }
144}
145
146
147void enqueue_event(pcep_session *session, pcep_event_type event_type,
148 struct pcep_message *message)
149{
150 if (event_type == MESSAGE_RECEIVED && message == NULL) {
151 pcep_log(
152 LOG_WARNING,
153 "%s: enqueue_event cannot enqueue a NULL message session [%d]",
154 __func__, session->session_id);
155 return;
156 }
157
158 pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event));
159 memset(event, 0, sizeof(pcep_event));
160
161 event->session = session;
162 event->event_type = event_type;
163 event->event_time = time(NULL);
164 event->message = message;
165
166 pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
167 if (session_logic_event_queue_->event_callback != NULL) {
168 session_logic_event_queue_->event_callback(
169 session_logic_event_queue_->event_callback_data, event);
170 } else {
171 queue_enqueue(session_logic_event_queue_->event_queue, event);
172 }
173 pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
174}
175
176/* Verify the received PCEP Open object parameters are acceptable. If not,
177 * update the unacceptable value(s) with an acceptable value so it can be sent
178 * back to the sender. */
179bool verify_pcep_open_object(pcep_session *session,
180 struct pcep_object_open *open_object)
181{
182 int retval = true;
183
184 if (open_object->open_keepalive
185 < session->pcc_config.min_keep_alive_seconds) {
186 pcep_log(
187 LOG_INFO,
188 "%s: Rejecting unsupported Open Keep Alive value [%d] min [%d]",
189 __func__, open_object->open_keepalive,
190 session->pcc_config.min_keep_alive_seconds);
191 open_object->open_keepalive =
192 session->pcc_config.min_keep_alive_seconds;
193 retval = false;
194 } else if (open_object->open_keepalive
195 > session->pcc_config.max_keep_alive_seconds) {
196 pcep_log(
197 LOG_INFO,
198 "%s: Rejecting unsupported Open Keep Alive value [%d] max [%d]",
199 __func__, open_object->open_keepalive,
200 session->pcc_config.max_keep_alive_seconds);
201 open_object->open_keepalive =
202 session->pcc_config.max_keep_alive_seconds;
203 retval = false;
204 }
205
206 if (open_object->open_deadtimer
207 < session->pcc_config.min_dead_timer_seconds) {
208 pcep_log(LOG_INFO,
209 "%s: Rejecting unsupported Open Dead Timer value [%d]",
210 __func__, open_object->open_deadtimer);
211 open_object->open_deadtimer =
212 session->pcc_config.min_dead_timer_seconds;
213 retval = false;
214 } else if (open_object->open_deadtimer
215 > session->pcc_config.max_dead_timer_seconds) {
216 pcep_log(LOG_INFO,
217 "%s: Rejecting unsupported Open Dead Timer value [%d]",
218 __func__, open_object->open_deadtimer);
219 open_object->open_deadtimer =
220 session->pcc_config.max_dead_timer_seconds;
221 retval = false;
222 }
223
224 /* Check for Open Object TLVs */
225 if (pcep_object_has_tlvs((struct pcep_object_header *)open_object)
226 == false) {
227 /* There are no TLVs, all done */
228 return retval;
229 }
230
231 double_linked_list_node *tlv_node = open_object->header.tlv_list->head;
232 while (tlv_node != NULL) {
233 struct pcep_object_tlv_header *tlv = tlv_node->data;
234 tlv_node = tlv_node->next_node;
235
236 /* Supported Open Object TLVs */
237 switch (tlv->type) {
238 case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION:
239 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
240 case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
241 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
242 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
243 break;
244
245 default:
246 /* TODO how to handle unrecognized TLV ?? */
247 pcep_log(
248 LOG_INFO,
249 "%s: Unhandled OPEN Object TLV type: %d, length %d",
250 __func__, tlv->type, tlv->encoded_tlv_length);
251 break;
252 }
253
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
257 *pce_cap_tlv =
258 (struct
259 pcep_object_tlv_stateful_pce_capability
260 *)tlv;
261
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
267 == false) {
268 /* Turn off the U bit, as it is not
269 * supported */
270 pcep_log(
271 LOG_INFO,
272 "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
273 __func__);
274 pce_cap_tlv
275 ->flag_u_lsp_update_capability =
276 false;
277 retval = false;
278 } else {
279 session->stateful_pce = true;
280 pcep_log(
281 LOG_INFO,
282 "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
283 __func__, session->session_id);
284 }
285 }
286 /* TODO the rest of the flags are not implemented yet */
287 else if (pce_cap_tlv->flag_s_include_db_version) {
288 pcep_log(
289 LOG_INFO,
290 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
291 __func__);
292 } else if (
293 pce_cap_tlv
294 ->flag_i_lsp_instantiation_capability) {
295 pcep_log(
296 LOG_INFO,
297 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
298 __func__);
299 } else if (pce_cap_tlv->flag_t_triggered_resync) {
300 pcep_log(
301 LOG_INFO,
302 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
303 __func__);
304 } else if (pce_cap_tlv->flag_d_delta_lsp_sync) {
305 pcep_log(
306 LOG_INFO,
307 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
308 __func__);
309 } else if (pce_cap_tlv->flag_f_triggered_initial_sync) {
310 pcep_log(
311 LOG_INFO,
312 "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
313 __func__);
314 }
315 } else if (tlv->type == PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION) {
316 if (session->pce_config.support_include_db_version
317 == false) {
318 pcep_log(
319 LOG_INFO,
320 "%s: Rejecting unsupported Open LSP DB VERSION TLV",
321 __func__);
322 /* Remove this TLV from the list */
323 dll_delete_node(open_object->header.tlv_list,
324 tlv_node);
325 retval = false;
326 }
327 }
328 }
329
330 return retval;
331}
332
333
334bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg)
335{
336 /* Open Message validation and errors according to:
337 * https://tools.ietf.org/html/rfc5440#section-7.15 */
338
339 if (session->session_state != SESSION_STATE_PCEP_CONNECTING
340 && session->session_state != SESSION_STATE_INITIALIZED) {
341 pcep_log(
342 LOG_INFO,
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);
348 return false;
349 }
350
351 if (session->pce_open_received == true
352 && session->pce_open_rejected == false) {
353 pcep_log(LOG_INFO,
354 "%s: Received duplicate OPEN, replying with error",
355 __func__);
356 send_pcep_error(session,
357 PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
358 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
359 return false;
360 }
361
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) {
366 pcep_log(
367 LOG_INFO,
368 "%s: Received OPEN message with no OPEN object, replying with error",
369 __func__);
370 send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
371 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
372 return false;
373 }
374
375 /* Check for additional Open Msg objects */
376 if (open_msg->obj_list->num_entries > 1) {
377 pcep_log(
378 LOG_INFO,
379 "%s: Found additional unsupported objects in the Open message, replying with error",
380 __func__);
381 send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
382 PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
383 return false;
384 }
385
386 session->pce_open_received = true;
387
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. */
395 pcep_log(
396 LOG_INFO,
397 "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
398 __func__);
399 send_pcep_error(
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);
406 } else {
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);
423 }
424
425 return false;
426 }
427
428 /*
429 * Open Message accepted
430 * Sending the keep-alive response will be managed the function caller
431 */
432
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);
441
442 return true;
443}
444
445
446/* The original PCEP Open message sent to the PCE was rejected,
447 * try to reconcile the differences and re-send a new Open. */
448void send_reconciled_pcep_open(pcep_session *session,
449 struct pcep_message *error_msg)
450{
451 struct pcep_message *open_msg = create_pcep_open(session);
452
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 */
458 pcep_log(
459 LOG_INFO,
460 "%s: No Open object received in Error, sending the same Open message",
461 __func__);
462 session_send_message(session, open_msg);
463 return;
464 }
465
466 struct pcep_object_open *open_obj =
467 (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
468 PCEP_OBJ_CLASS_OPEN);
7ed8c4b1
JG
469 // open_msg can not have empty obj_list
470 assert(open_obj != NULL);
74971473
JG
471
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;
482 pcep_log(
483 LOG_INFO,
484 "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
485 __func__,
486 session->pcc_config.dead_timer_seconds,
487 session->pcc_config
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);
493 } else {
494 pcep_log(
495 LOG_INFO,
496 "%s: Can not reconcile Open with suggested deadtimer [%d]",
497 __func__, error_open_obj->open_deadtimer);
498 }
499 }
500
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;
509 session->pcc_config
510 .keep_alive_pce_negotiated_timer_seconds =
511 error_open_obj->open_keepalive;
512 pcep_log(
513 LOG_INFO,
514 "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
515 __func__,
516 session->pcc_config.keep_alive_seconds,
517 session->pcc_config
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;
523 } else {
524 pcep_log(
525 LOG_INFO,
526 "%s: Can not reconcile Open with suggested keepalive [%d]",
527 __func__, error_open_obj->open_keepalive);
528 }
529 }
530
531 /* TODO reconcile the TLVs */
532
533 session_send_message(session, open_msg);
534 reset_timer(session->timer_id_open_keep_alive);
535}
536
537
538bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg)
539{
540 /* Update Message validation and errors according to:
541 * https://tools.ietf.org/html/rfc8231#section-6.2 */
542
543 if (upd_msg->obj_list == NULL) {
544 pcep_log(LOG_INFO,
545 "%s: Invalid PcUpd message: Message has no objects",
546 __func__);
547 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
548 PCEP_ERRV_SRP_OBJECT_MISSING);
549 return false;
550 }
551
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);
555 if (obj == NULL) {
556 pcep_log(LOG_INFO,
557 "%s: Invalid PcUpd message: Missing SRP object",
558 __func__);
559 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
560 PCEP_ERRV_SRP_OBJECT_MISSING);
561 return false;
562 }
563
564 obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_LSP);
565 if (obj == NULL) {
566 pcep_log(LOG_INFO,
567 "%s: Invalid PcUpd message: Missing LSP object",
568 __func__);
569 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
570 PCEP_ERRV_LSP_OBJECT_MISSING);
571 return false;
572 }
573
574 obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_ERO);
575 if (obj == NULL) {
576 pcep_log(LOG_INFO,
577 "%s: Invalid PcUpd message: Missing ERO object",
578 __func__);
579 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
580 PCEP_ERRV_ERO_OBJECT_MISSING);
581 return false;
582 }
583
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) {
589 pcep_log(
590 LOG_INFO,
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);
595 return false;
596 }
597
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) {
602 pcep_log(
603 LOG_INFO,
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);
608 return false;
609 }
610
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) {
614 pcep_log(
615 LOG_INFO,
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);
620 return false;
621 }
622
623 return true;
624}
625
626bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg)
627{
628 /* Instantiate Message validation and errors according to:
629 * https://tools.ietf.org/html/rfc8281#section-5 */
630
631 if (init_msg->obj_list == NULL) {
632 pcep_log(
633 LOG_INFO,
634 "%s: Invalid PcInitiate message: Message has no objects",
635 __func__);
636 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
637 PCEP_ERRV_SRP_OBJECT_MISSING);
638 return false;
639 }
640
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);
644 if (obj == NULL) {
645 pcep_log(LOG_INFO,
646 "%s: Invalid PcInitiate message: Missing SRP object",
647 __func__);
648 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
649 PCEP_ERRV_SRP_OBJECT_MISSING);
650 return false;
651 }
652
653 obj = pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_LSP);
654 if (obj == NULL) {
655 pcep_log(LOG_INFO,
656 "%s: Invalid PcInitiate message: Missing LSP object",
657 __func__);
658 send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
659 PCEP_ERRV_LSP_OBJECT_MISSING);
660 return false;
661 }
662
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) {
668 pcep_log(
669 LOG_INFO,
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);
674 return false;
675 }
676
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) {
681 pcep_log(
682 LOG_INFO,
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);
687 return false;
688 }
689
690 /* There may be more optional objects */
691 return true;
692}
693
694void increment_unknown_message(pcep_session *session)
695{
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 */
700
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);
707
708 /* Purge any entries older than 1 minute. The oldest entries are at the
709 * queue head */
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) {
713 pceplib_free(
714 PCEPLIB_INFRA,
715 queue_dequeue(
716 session->num_unknown_messages_time_queue));
717 time_node =
718 session->num_unknown_messages_time_queue->head;
719 } else {
720 time_node = NULL;
721 }
722 }
723
724 if ((int)session->num_unknown_messages_time_queue->num_entries
725 >= session->pcc_config.max_unknown_messages) {
726 pcep_log(
727 LOG_INFO,
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);
732
733 close_pcep_session_with_reason(session,
734 PCEP_CLOSE_REASON_UNREC_MSG);
735 enqueue_event(session, PCC_RCVD_MAX_UNKOWN_MSGS, NULL);
736 }
737}
738
739bool check_and_send_open_keep_alive(pcep_session *session)
740{
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
745 * yet */
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;
750
751 return true;
752 }
753
754 return false;
755}
756
757void log_pcc_pce_connection(pcep_session *session)
758{
759 if (session->socket_comm_session == NULL) {
760 /* This only happens in UT */
761 return;
762 }
763
764 char src_ip_buf[40] = {0}, dst_ip_buf[40] = {0};
765 uint16_t src_port, dst_port;
766
767 if (session->socket_comm_session->is_ipv6) {
768 inet_ntop(AF_INET6,
769 &session->socket_comm_session->src_sock_addr
770 .src_sock_addr_ipv6.sin6_addr,
771 src_ip_buf, sizeof(src_ip_buf));
772 inet_ntop(AF_INET6,
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);
780 } else {
781 inet_ntop(AF_INET,
782 &session->socket_comm_session->src_sock_addr
783 .src_sock_addr_ipv4.sin_addr,
784 src_ip_buf, sizeof(src_ip_buf));
785 inet_ntop(AF_INET,
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);
793 }
794
795 pcep_log(
796 LOG_INFO,
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);
801}
802
803/*
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.
808 */
809
810/* state machine handling for expired timers */
811void handle_timer_event(pcep_session_event *event)
812{
813 if (event == NULL) {
814 pcep_log(LOG_INFO, "%s: handle_timer_event NULL event",
815 __func__);
816 return;
817 }
818
819 pcep_session *session = event->session;
820
821 pcep_log(
822 LOG_INFO,
d85bf6f1 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]",
74971473
JG
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);
828
829 /*
830 * these timer expirations are independent of the session state
831 */
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);
839 return;
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);
845 return;
846 }
847
848 /*
849 * handle timers that depend on the session state
850 */
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 */
856 pcep_log(
857 LOG_INFO,
858 "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
859 __func__, session->session_id);
860 increment_event_counters(
861 session,
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,
868 NULL);
869 }
870
871 if (event->expired_timer_id
872 == session->timer_id_open_keep_alive) {
873 increment_event_counters(
874 session,
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(
885 session,
886 PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
887 enqueue_event(session,
888 PCC_CONNECTED_TO_PCE,
889 NULL);
890 }
891 }
892 return;
893 }
894 break;
895
896 case SESSION_STATE_INITIALIZED:
897 case SESSION_STATE_PCEP_CONNECTED:
898 default:
899 pcep_log(
900 LOG_INFO,
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);
904 break;
905 }
906}
907
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 */
911void handle_socket_comm_event(pcep_session_event *event)
912{
913 if (event == NULL) {
914 pcep_log(LOG_INFO, "%s: handle_socket_comm_event NULL event",
915 __func__);
916 return;
917 }
918
919 pcep_session *session = event->session;
920
921 pcep_log(
922 LOG_INFO,
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
926 ? -1
927 : (int)event->received_msg_list->num_entries),
928 event->socket_closed);
929
930 /*
931 * independent of the session state
932 */
933 if (event->socket_closed) {
934 pcep_log(
935 LOG_INFO,
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);
942 }
943 session->session_state = SESSION_STATE_INITIALIZED;
944 increment_event_counters(session,
945 PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
946 return;
947 }
948
949 reset_dead_timer(session);
950
951 if (event->received_msg_list == NULL) {
952 return;
953 }
954
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));
964
965 increment_message_rx_counters(session, msg);
966
967 switch (msg->msg_header->type) {
968 case PCEP_TYPE_OPEN:
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
982 * connected */
983
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(
989 session,
990 PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
991 enqueue_event(session,
992 PCC_CONNECTED_TO_PCE,
993 NULL);
994 }
995 }
996 break;
997
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 =
1004 TIMER_ID_NOT_SET;
1005 session->pcc_open_accepted = true;
1006 session->pcc_open_rejected = false;
1007 check_and_send_open_keep_alive(session);
1008
1009 if (session->pce_open_accepted) {
1010 /* If both the PCC and PCE Opens are
1011 * accepted, then the session is
1012 * connected */
1013 log_pcc_pce_connection(session);
1014 session->session_state =
1015 SESSION_STATE_PCEP_CONNECTED;
1016 increment_event_counters(
1017 session,
1018 PCEP_EVENT_COUNTER_ID_PCC_CONNECT);
1019 enqueue_event(session,
1020 PCC_CONNECTED_TO_PCE,
1021 NULL);
1022 }
1023 }
1024 /* The dead_timer was already reset above, so nothing
1025 * extra to do here */
1026 break;
1027
1028 case PCEP_TYPE_PCREP:
1029 enqueue_event(session, MESSAGE_RECEIVED, msg);
1030 message_enqueued = true;
1031 break;
1032
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);
1044 break;
1045
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);
1051 break;
1052
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);
1058 break;
1059
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;
1065 }
1066 break;
1067
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;
1073 }
1074 break;
1075
1076 case PCEP_TYPE_PCNOTF:
1077 enqueue_event(session, MESSAGE_RECEIVED, msg);
1078 message_enqueued = true;
1079 break;
1080
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 *)
1090 obj_hdr;
1091 pcep_log(
1092 LOG_DEBUG,
1093 "%s: Error object [type, value] = [%s, %s]",
1094 __func__,
1095 get_error_type_str(
1096 error_obj->error_type),
1097 get_error_value_str(
1098 error_obj->error_type,
1099 error_obj
1100 ->error_value));
1101 }
1102 }
1103
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.
1110 */
1111 pcep_log(LOG_INFO,
1112 "%s: PCC Open message rejected by PCE",
1113 __func__);
1114 session->pcc_open_rejected = true;
1115 send_reconciled_pcep_open(session, msg);
1116 enqueue_event(session, PCC_SENT_INVALID_OPEN,
1117 NULL);
1118 }
1119 enqueue_event(session, MESSAGE_RECEIVED, msg);
1120 message_enqueued = true;
1121 break;
1122
1123 default:
1124 pcep_log(LOG_INFO, "%s: \t UnSupported message",
1125 __func__);
1126 send_pcep_error(session,
1127 PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
1128 PCEP_ERRV_UNASSIGNED);
1129 increment_unknown_message(session);
1130 break;
1131 }
1132
1133 /* if the message was enqueued, dont free it yet */
1134 if (message_enqueued == false) {
1135 pcep_msg_free_message(msg);
1136 }
1137 }
1138 dll_destroy(event->received_msg_list);
1139}