2 * Copyright (C) 2020 NetDEF, Inc.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along
15 * with this program; see the file COPYING; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "lib/version.h"
26 #include "northbound.h"
27 #include "frr_pthread.h"
31 #include "pathd/pathd.h"
32 #include "pathd/path_errors.h"
33 #include "pathd/path_pcep.h"
34 #include "pathd/path_pcep_controller.h"
35 #include "pathd/path_pcep_pcc.h"
36 #include "pathd/path_pcep_config.h"
37 #include "pathd/path_pcep_debug.h"
39 #define MAX_RECONNECT_DELAY 120
43 __typeof__(a) _a = (a); \
44 __typeof__(b) _b = (b); \
49 /* Event handling data structures */
50 enum pcep_ctrl_event_type
{
51 EV_UPDATE_PCC_OPTS
= 1,
64 struct pcep_ctrl_event_data
{
65 struct ctrl_state
*ctrl_state
;
66 enum pcep_ctrl_event_type type
;
72 struct pcep_main_event_data
{
73 pcep_main_event_handler_t handler
;
75 enum pcep_main_event_type type
;
79 struct pcep_refine_path_event_data
{
80 struct ctrl_state
*ctrl_state
;
82 pcep_refine_callback_t continue_lsp_update_handler
;
87 /* Synchronous call arguments */
89 struct get_counters_args
{
90 struct ctrl_state
*ctrl_state
;
92 struct counters_group
*counters
;
95 struct get_pcep_session_args
{
96 struct ctrl_state
*ctrl_state
;
98 pcep_session
*pcep_session
;
101 /* Internal Functions Called From Main Thread */
102 static int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
);
103 static int pcep_refine_path_event_cb(struct thread
*thread
);
105 /* Internal Functions Called From Controller Thread */
106 static int pcep_thread_finish_event_handler(struct thread
*thread
);
108 /* Controller Thread Timer Handler */
109 static int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
110 enum pcep_ctrl_timer_type timer_type
,
111 enum pcep_ctrl_timeout_type timeout_type
,
112 uint32_t delay
, void *payload
,
113 struct thread
**thread
);
114 static int schedule_thread_timer_with_cb(
115 struct ctrl_state
*ctrl_state
, int pcc_id
,
116 enum pcep_ctrl_timer_type timer_type
,
117 enum pcep_ctrl_timeout_type timeout_type
, uint32_t delay
, void *payload
,
118 struct thread
**thread
, pcep_ctrl_thread_callback timer_cb
);
119 static int pcep_thread_timer_handler(struct thread
*thread
);
121 /* Controller Thread Socket read/write Handler */
122 static int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
123 enum pcep_ctrl_socket_type type
, bool is_read
,
124 void *payload
, int fd
, struct thread
**thread
,
125 pcep_ctrl_thread_callback cb
);
127 /* Controller Thread Event Handler */
128 static int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
129 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
131 static int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
132 enum pcep_ctrl_event_type type
,
133 uint32_t sub_type
, void *payload
,
134 pcep_ctrl_thread_callback event_cb
);
135 static int pcep_thread_event_handler(struct thread
*thread
);
136 static int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
137 struct pcc_opts
*opts
);
138 static int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
140 struct pce_opts
*opts
);
141 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
143 static int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
);
144 static int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
145 struct pce_opts
*pce_opts
);
146 static int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
,
147 int pcc_id
, struct path
*path
);
148 static int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
,
150 static int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
151 enum pcep_pathd_event_type type
,
154 pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
155 struct pcep_refine_path_event_data
*data
);
157 /* Main Thread Event Handler */
158 static int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
159 enum pcep_main_event_type type
, void *payload
);
160 static int pcep_main_event_handler(struct thread
*thread
);
162 /* Helper functions */
163 static void set_ctrl_state(struct frr_pthread
*fpt
,
164 struct ctrl_state
*ctrl_state
);
165 static struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
);
166 int get_next_id(struct ctrl_state
*ctrl_state
);
167 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
);
168 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
169 struct pcc_state
*pcc_state
);
170 static uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t attempt
);
171 static const char *timer_type_name(enum pcep_ctrl_timer_type type
);
172 static const char *timeout_type_name(enum pcep_ctrl_timeout_type type
);
175 /* ------------ API Functions Called from Main Thread ------------ */
177 int pcep_ctrl_initialize(struct thread_master
*main_thread
,
178 struct frr_pthread
**fpt
,
179 pcep_main_event_handler_t event_handler
)
184 struct ctrl_state
*ctrl_state
;
185 struct frr_pthread_attr attr
= {
186 .start
= frr_pthread_attr_default
.start
,
187 .stop
= pcep_ctrl_halt_cb
,
190 PCEP_DEBUG("Initializing pcep module controller");
192 /* Create and start the FRR pthread */
193 *fpt
= frr_pthread_new(&attr
, "PCEP thread", "pcep_controller");
195 flog_err(EC_PATH_SYSTEM_CALL
,
196 "failed to initialize PCEP thread");
199 ret
= frr_pthread_run(*fpt
, NULL
);
201 flog_err(EC_PATH_SYSTEM_CALL
, "failed to create PCEP thread");
204 frr_pthread_wait_running(*fpt
);
206 /* Initialize the thread state */
207 ctrl_state
= XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
));
208 ctrl_state
->main
= main_thread
;
209 ctrl_state
->self
= (*fpt
)->master
;
210 ctrl_state
->main_event_handler
= event_handler
;
211 ctrl_state
->pcc_count
= 0;
212 ctrl_state
->pcc_last_id
= 0;
213 ctrl_state
->pcc_opts
=
214 XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
->pcc_opts
));
215 /* Default to no PCC address defined */
216 ctrl_state
->pcc_opts
->addr
.ipa_type
= IPADDR_NONE
;
217 ctrl_state
->pcc_opts
->port
= PCEP_DEFAULT_PORT
;
219 /* Keep the state reference for events */
220 set_ctrl_state(*fpt
, ctrl_state
);
225 int pcep_ctrl_finalize(struct frr_pthread
**fpt
)
231 PCEP_DEBUG("Finalizing pcep module controller");
234 frr_pthread_stop(*fpt
, NULL
);
241 int pcep_ctrl_update_pcc_options(struct frr_pthread
*fpt
, struct pcc_opts
*opts
)
243 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
244 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCC_OPTS
, 0, opts
);
247 int pcep_ctrl_update_pce_options(struct frr_pthread
*fpt
, struct pce_opts
*opts
)
249 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
250 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCE_OPTS
, 0, opts
);
253 int pcep_ctrl_remove_pcc(struct frr_pthread
*fpt
, struct pce_opts
*pce_opts
)
255 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
256 return send_to_thread(ctrl_state
, 0, EV_REMOVE_PCC
, 0, pce_opts
);
259 int pcep_ctrl_reset_pcc_session(struct frr_pthread
*fpt
, char *pce_name
)
261 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
262 return send_to_thread(ctrl_state
, 0, EV_RESET_PCC_SESSION
, 0, pce_name
);
265 int pcep_ctrl_pathd_event(struct frr_pthread
*fpt
,
266 enum pcep_pathd_event_type type
, struct path
*path
)
268 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
269 return send_to_thread(ctrl_state
, 0, EV_PATHD_EVENT
, type
, path
);
272 int pcep_ctrl_sync_path(struct frr_pthread
*fpt
, int pcc_id
, struct path
*path
)
274 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
275 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_PATH
, 0, path
);
278 int pcep_ctrl_sync_done(struct frr_pthread
*fpt
, int pcc_id
)
280 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
281 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_DONE
, 0, NULL
);
284 struct counters_group
*pcep_ctrl_get_counters(struct frr_pthread
*fpt
,
287 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
288 struct counters_group
*counters
= NULL
;
289 struct pcc_state
*pcc_state
;
290 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
292 counters
= pcep_lib_copy_counters(pcc_state
->sess
);
297 pcep_session
*pcep_ctrl_get_pcep_session(struct frr_pthread
*fpt
, int pcc_id
)
299 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
300 struct pcc_state
*pcc_state
;
301 pcep_session
*session
= NULL
;
303 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
305 session
= pcep_lib_copy_pcep_session(pcc_state
->sess
);
310 struct pcep_pcc_info
*pcep_ctrl_get_pcc_info(struct frr_pthread
*fpt
,
311 const char *pce_name
)
313 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
314 struct pcep_pcc_info
*pcc_info
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_info
));
315 if( pcc_info
&& ctrl_state
){
316 strlcpy(pcc_info
->pce_name
, pce_name
, sizeof(pcc_info
->pce_name
));
317 pcep_pcc_copy_pcc_info(ctrl_state
->pcc
, pcc_info
);
323 int pcep_ctrl_send_report(struct frr_pthread
*fpt
, int pcc_id
,
324 struct path
*path
, bool is_stable
)
326 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
327 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_REPORT
, is_stable
,
332 int pcep_ctrl_send_error(struct frr_pthread
*fpt
, int pcc_id
,
333 struct pcep_error
*error
)
335 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
336 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_ERROR
, 0, error
);
340 /* ------------ Internal Functions Called from Main Thread ------------ */
342 int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
)
344 thread_add_event(fpt
->master
, pcep_thread_finish_event_handler
,
345 (void *)fpt
, 0, NULL
);
346 pthread_join(fpt
->thread
, res
);
351 int pcep_refine_path_event_cb(struct thread
*thread
)
353 struct pcep_refine_path_event_data
*data
= THREAD_ARG(thread
);
354 assert(data
!= NULL
);
355 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
356 struct path
*path
= data
->path
;
357 assert(path
!= NULL
);
358 int pcc_id
= data
->pcc_id
;
361 path_pcep_refine_path(path
);
362 return send_to_thread(ctrl_state
, pcc_id
, EV_PATH_REFINED
, 0, data
);
366 /* ------------ API Functions Called From Controller Thread ------------ */
368 void pcep_thread_start_sync(struct ctrl_state
*ctrl_state
, int pcc_id
)
370 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_START_SYNC
, NULL
);
373 void pcep_thread_update_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
376 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_UPDATE_CANDIDATE
,
380 void pcep_thread_initiate_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
383 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_INITIATE_CANDIDATE
,
387 void pcep_thread_remove_candidate_path_segments(struct ctrl_state
*ctrl_state
,
388 struct pcc_state
*pcc_state
)
392 /* Will be deleted when the event is handled */
393 char *originator
= XSTRDUP(MTYPE_PCEP
, pcc_state
->originator
);
394 PCEP_DEBUG("schedule candidate path segments removal for originator %s",
396 send_to_main(ctrl_state
, pcep_pcc_get_pcc_id(pcc_state
),
397 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
, originator
);
400 void pcep_thread_schedule_sync_best_pce(struct ctrl_state
*ctrl_state
,
401 int pcc_id
, int delay
,
402 struct thread
**thread
)
405 schedule_thread_timer(ctrl_state
, pcc_id
, TM_CALCULATE_BEST_PCE
,
406 TO_UNDEFINED
, delay
, NULL
, thread
);
409 void pcep_thread_cancel_timer(struct thread
**thread
)
411 if (thread
== NULL
|| *thread
== NULL
) {
415 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(*thread
);
416 PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data
->timer_type
),
417 timeout_type_name(data
->timeout_type
));
419 XFREE(MTYPE_PCEP
, data
);
422 if ((*thread
)->master
->owner
== pthread_self()) {
423 thread_cancel(thread
);
425 thread_cancel_async((*thread
)->master
, thread
, NULL
);
429 void pcep_thread_schedule_reconnect(struct ctrl_state
*ctrl_state
, int pcc_id
,
430 int retry_count
, struct thread
**thread
)
432 uint32_t delay
= backoff_delay(MAX_RECONNECT_DELAY
, 1, retry_count
);
433 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay
,
435 schedule_thread_timer(ctrl_state
, pcc_id
, TM_RECONNECT_PCC
,
436 TO_UNDEFINED
, delay
, NULL
, thread
);
439 void pcep_thread_schedule_timeout(struct ctrl_state
*ctrl_state
, int pcc_id
,
440 enum pcep_ctrl_timeout_type timeout_type
,
441 uint32_t delay
, void *param
,
442 struct thread
**thread
)
444 assert(timeout_type
> TO_UNDEFINED
);
445 assert(timeout_type
< TO_MAX
);
446 PCEP_DEBUG("Schedule timeout %s for %us",
447 timeout_type_name(timeout_type
), delay
);
448 schedule_thread_timer(ctrl_state
, pcc_id
, TM_TIMEOUT
, timeout_type
,
449 delay
, param
, thread
);
452 void pcep_thread_schedule_pceplib_timer(struct ctrl_state
*ctrl_state
,
453 int delay
, void *payload
,
454 struct thread
**thread
,
455 pcep_ctrl_thread_callback timer_cb
)
457 PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay
);
458 schedule_thread_timer_with_cb(ctrl_state
, 0, TM_PCEPLIB_TIMER
,
459 TO_UNDEFINED
, delay
, payload
, thread
,
463 void pcep_thread_schedule_session_timeout(struct ctrl_state
*ctrl_state
,
464 int pcc_id
, int delay
,
465 struct thread
**thread
)
467 PCEP_DEBUG("Schedule session_timeout interval for %us", delay
);
468 schedule_thread_timer(ctrl_state
, pcc_id
, TM_SESSION_TIMEOUT_PCC
,
469 TO_UNDEFINED
, delay
, NULL
, thread
);
472 int pcep_thread_pcc_count(struct ctrl_state
*ctrl_state
)
474 if (ctrl_state
== NULL
) {
478 return ctrl_state
->pcc_count
;
481 int pcep_thread_refine_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
482 pcep_refine_callback_t cb
, struct path
*path
,
485 struct pcep_refine_path_event_data
*data
;
487 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
488 data
->ctrl_state
= ctrl_state
;
490 data
->pcc_id
= pcc_id
;
491 data
->continue_lsp_update_handler
= cb
;
492 data
->payload
= payload
;
494 thread_add_event(ctrl_state
->main
, pcep_refine_path_event_cb
,
495 (void *)data
, 0, NULL
);
499 void pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
500 struct pcep_refine_path_event_data
*data
)
502 assert(data
!= NULL
);
503 int pcc_id
= data
->pcc_id
;
504 pcep_refine_callback_t continue_lsp_update_handler
= data
->continue_lsp_update_handler
;
505 assert(continue_lsp_update_handler
!= NULL
);
506 struct path
*path
= data
->path
;
507 void *payload
= data
->payload
;
508 struct pcc_state
*pcc_state
= NULL
;
509 XFREE(MTYPE_PCEP
, data
);
511 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
512 continue_lsp_update_handler(ctrl_state
, pcc_state
, path
, payload
);
516 /* ------------ Internal Functions Called From Controller Thread ------------ */
518 int pcep_thread_finish_event_handler(struct thread
*thread
)
521 struct frr_pthread
*fpt
= THREAD_ARG(thread
);
522 struct ctrl_state
*ctrl_state
= fpt
->data
;
524 assert(ctrl_state
!= NULL
);
526 for (i
= 0; i
< MAX_PCC
; i
++) {
527 if (ctrl_state
->pcc
[i
]) {
528 pcep_pcc_finalize(ctrl_state
, ctrl_state
->pcc
[i
]);
529 ctrl_state
->pcc
[i
] = NULL
;
533 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
534 XFREE(MTYPE_PCEP
, ctrl_state
);
537 atomic_store_explicit(&fpt
->running
, false, memory_order_relaxed
);
541 /* ------------ Controller Thread Timer Handler ------------ */
543 int schedule_thread_timer_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
544 enum pcep_ctrl_timer_type timer_type
,
545 enum pcep_ctrl_timeout_type timeout_type
,
546 uint32_t delay
, void *payload
,
547 struct thread
**thread
,
548 pcep_ctrl_thread_callback timer_cb
)
550 assert(thread
!= NULL
);
552 struct pcep_ctrl_timer_data
*data
;
554 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
555 data
->ctrl_state
= ctrl_state
;
556 data
->timer_type
= timer_type
;
557 data
->timeout_type
= timeout_type
;
558 data
->pcc_id
= pcc_id
;
559 data
->payload
= payload
;
561 thread_add_timer(ctrl_state
->self
, timer_cb
, (void *)data
, delay
,
567 int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
568 enum pcep_ctrl_timer_type timer_type
,
569 enum pcep_ctrl_timeout_type timeout_type
,
570 uint32_t delay
, void *payload
, struct thread
**thread
)
572 return schedule_thread_timer_with_cb(ctrl_state
, pcc_id
, timer_type
,
573 timeout_type
, delay
, payload
,
574 thread
, pcep_thread_timer_handler
);
577 int pcep_thread_timer_handler(struct thread
*thread
)
580 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(thread
);
581 assert(data
!= NULL
);
582 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
583 assert(ctrl_state
!= NULL
);
584 enum pcep_ctrl_timer_type timer_type
= data
->timer_type
;
585 enum pcep_ctrl_timeout_type timeout_type
= data
->timeout_type
;
586 int pcc_id
= data
->pcc_id
;
587 void *param
= data
->payload
;
588 XFREE(MTYPE_PCEP
, data
);
591 struct pcc_state
*pcc_state
= NULL
;
593 switch (timer_type
) {
594 case TM_RECONNECT_PCC
:
595 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
598 pcep_pcc_reconnect(ctrl_state
, pcc_state
);
601 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
604 pcep_pcc_timeout_handler(ctrl_state
, pcc_state
, timeout_type
,
607 case TM_CALCULATE_BEST_PCE
:
608 /* Previous best disconnect so new best should be synced */
609 ret
= pcep_pcc_timer_update_best_pce(ctrl_state
, pcc_id
);
611 case TM_SESSION_TIMEOUT_PCC
:
612 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
613 pcep_thread_remove_candidate_path_segments(ctrl_state
,
617 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
618 "Unknown controller timer triggered: %u", timer_type
);
625 int pcep_thread_pcep_event(struct thread
*thread
)
627 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
628 assert(data
!= NULL
);
629 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
630 pcep_event
*event
= data
->payload
;
631 XFREE(MTYPE_PCEP
, data
);
634 for (i
= 0; i
< MAX_PCC
; i
++) {
635 if (ctrl_state
->pcc
[i
]) {
636 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
637 if (pcc_state
->sess
!= event
->session
)
639 pcep_pcc_pcep_event_handler(ctrl_state
, pcc_state
,
644 destroy_pcep_event(event
);
649 /* ------------ Controller Thread Socket Functions ------------ */
651 int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
652 enum pcep_ctrl_socket_type type
, bool is_read
,
653 void *payload
, int fd
, struct thread
**thread
,
654 pcep_ctrl_thread_callback socket_cb
)
656 assert(thread
!= NULL
);
658 struct pcep_ctrl_socket_data
*data
;
660 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
661 data
->ctrl_state
= ctrl_state
;
663 data
->is_read
= is_read
;
665 data
->pcc_id
= pcc_id
;
666 data
->payload
= payload
;
669 thread_add_read(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
672 thread_add_write(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
679 int pcep_thread_socket_write(void *fpt
, void **thread
, int fd
, void *payload
,
680 pcep_ctrl_thread_callback socket_cb
)
682 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
684 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, false,
685 payload
, fd
, (struct thread
**)thread
,
689 int pcep_thread_socket_read(void *fpt
, void **thread
, int fd
, void *payload
,
690 pcep_ctrl_thread_callback socket_cb
)
692 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
694 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, true,
695 payload
, fd
, (struct thread
**)thread
,
699 int pcep_thread_send_ctrl_event(void *fpt
, void *payload
,
700 pcep_ctrl_thread_callback cb
)
702 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
704 return send_to_thread_with_cb(ctrl_state
, 0, EV_PCEPLIB_EVENT
, 0,
708 /* ------------ Controller Thread Event Handler ------------ */
710 int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
711 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
714 return send_to_thread_with_cb(ctrl_state
, pcc_id
, type
, sub_type
,
715 payload
, pcep_thread_event_handler
);
718 int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
719 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
720 void *payload
, pcep_ctrl_thread_callback event_cb
)
722 struct pcep_ctrl_event_data
*data
;
724 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
725 data
->ctrl_state
= ctrl_state
;
727 data
->sub_type
= sub_type
;
728 data
->pcc_id
= pcc_id
;
729 data
->payload
= payload
;
731 thread_add_event(ctrl_state
->self
, event_cb
, (void *)data
, 0, NULL
);
736 int pcep_thread_event_handler(struct thread
*thread
)
739 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
740 assert(data
!= NULL
);
741 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
742 assert(ctrl_state
!= NULL
);
743 enum pcep_ctrl_event_type type
= data
->type
;
744 uint32_t sub_type
= data
->sub_type
;
745 int pcc_id
= data
->pcc_id
;
746 void *payload
= data
->payload
;
747 XFREE(MTYPE_PCEP
, data
);
751 /* Possible sub-type values */
752 enum pcep_pathd_event_type path_event_type
= PCEP_PATH_UNDEFINED
;
754 /* Possible payload values, maybe an union would be better... */
755 struct path
*path
= NULL
;
756 struct pcc_opts
*pcc_opts
= NULL
;
757 struct pce_opts
*pce_opts
= NULL
;
758 struct pcc_state
*pcc_state
= NULL
;
759 struct pcep_refine_path_event_data
*refine_data
= NULL
;
761 struct path
*path_copy
= NULL
;
762 struct pcep_error
*error
= NULL
;
765 case EV_UPDATE_PCC_OPTS
:
766 assert(payload
!= NULL
);
767 pcc_opts
= (struct pcc_opts
*)payload
;
768 ret
= pcep_thread_event_update_pcc_options(ctrl_state
,
771 case EV_UPDATE_PCE_OPTS
:
772 assert(payload
!= NULL
);
773 pce_opts
= (struct pce_opts
*)payload
;
774 ret
= pcep_thread_event_update_pce_options(ctrl_state
, pcc_id
,
778 pce_opts
= (struct pce_opts
*)payload
;
779 ret
= pcep_thread_event_remove_pcc(ctrl_state
, pce_opts
);
781 ret
= pcep_pcc_multi_pce_remove_pcc(ctrl_state
,
786 assert(payload
!= NULL
);
787 path_event_type
= (enum pcep_pathd_event_type
)sub_type
;
788 path
= (struct path
*)payload
;
789 ret
= pcep_thread_event_pathd_event(ctrl_state
, path_event_type
,
793 assert(payload
!= NULL
);
794 path
= (struct path
*)payload
;
795 pcep_pcc_multi_pce_sync_path(ctrl_state
, pcc_id
,
797 pcep_thread_event_sync_path(ctrl_state
, pcc_id
, path
);
800 ret
= pcep_thread_event_sync_done(ctrl_state
, pcc_id
);
802 case EV_RESET_PCC_SESSION
:
803 pcc_state
= pcep_pcc_get_pcc_by_name(ctrl_state
->pcc
,
804 (const char *)payload
);
806 pcep_pcc_disable(ctrl_state
, pcc_state
);
807 ret
= pcep_pcc_enable(ctrl_state
, pcc_state
);
809 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
810 "Cannot reset state for PCE: %s",
811 (const char *)payload
);
815 assert(payload
!= NULL
);
816 path
= (struct path
*)payload
;
818 for (int i
= 0; i
< MAX_PCC
; i
++) {
819 if (ctrl_state
->pcc
[i
]) {
820 path_copy
= pcep_copy_path(path
);
821 pcep_pcc_send_report(
822 ctrl_state
, ctrl_state
->pcc
[i
],
823 path_copy
, (bool)sub_type
);
828 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
829 pcep_pcc_send_report(ctrl_state
, pcc_state
, path
,
833 case EV_PATH_REFINED
:
834 assert(payload
!= NULL
);
835 refine_data
= (struct pcep_refine_path_event_data
*)payload
;
836 pcep_thread_path_refined_event(ctrl_state
, refine_data
);
839 assert(payload
!= NULL
);
840 error
= (struct pcep_error
*)payload
;
841 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
842 pcep_pcc_send_error(ctrl_state
, pcc_state
, error
,
846 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
847 "Unexpected event received in controller thread: %u",
855 int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
856 struct pcc_opts
*opts
)
858 assert(opts
!= NULL
);
859 if (ctrl_state
->pcc_opts
!= NULL
) {
860 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
862 ctrl_state
->pcc_opts
= opts
;
866 int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
867 int pcc_id
, struct pce_opts
*pce_opts
)
869 if (!pce_opts
|| !ctrl_state
) {
872 struct pcc_state
*pcc_state
;
873 struct pcc_opts
*pcc_opts
;
876 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
, pce_opts
);
877 if (current_pcc_id
) {
879 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, current_pcc_id
);
881 pcc_state
= pcep_pcc_initialize(ctrl_state
,
882 get_next_id(ctrl_state
));
883 if (set_pcc_state(ctrl_state
, pcc_state
)) {
884 XFREE(MTYPE_PCEP
, pcc_state
);
889 /* Copy the pcc options to delegate it to the update function */
890 pcc_opts
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_opts
));
891 memcpy(pcc_opts
, ctrl_state
->pcc_opts
, sizeof(*pcc_opts
));
893 if (pcep_pcc_update(ctrl_state
, pcc_state
, pcc_opts
, pce_opts
)) {
894 flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE
,
895 "failed to update PCC configuration");
902 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
906 struct pcc_state
*pcc_state
=
907 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
909 remove_pcc_state(ctrl_state
, pcc_state
);
910 pcep_pcc_finalize(ctrl_state
, pcc_state
);
916 int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
)
918 assert(ctrl_state
!= NULL
);
920 for (int i
= 0; i
< MAX_PCC
; i
++) {
921 pcep_thread_event_remove_pcc_by_id(
923 pcep_pcc_get_pcc_id_by_idx(ctrl_state
->pcc
, i
));
928 int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
929 struct pce_opts
*pce_opts
)
931 assert(ctrl_state
!= NULL
);
934 int pcc_id
= pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
,
937 pcep_thread_event_remove_pcc_by_id(ctrl_state
, pcc_id
);
941 XFREE(MTYPE_PCEP
, pce_opts
);
943 pcep_thread_event_remove_pcc_all(ctrl_state
);
949 int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
952 struct pcc_state
*pcc_state
=
953 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
954 pcep_pcc_sync_path(ctrl_state
, pcc_state
, path
);
955 pcep_free_path(path
);
959 int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
, int pcc_id
)
961 struct pcc_state
*pcc_state
=
962 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
963 pcep_pcc_sync_done(ctrl_state
, pcc_state
);
967 int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
968 enum pcep_pathd_event_type type
,
973 for (i
= 0; i
< MAX_PCC
; i
++) {
974 if (ctrl_state
->pcc
[i
]) {
975 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
976 pcep_pcc_pathd_event_handler(ctrl_state
, pcc_state
,
981 pcep_free_path(path
);
987 /* ------------ Main Thread Event Handler ------------ */
989 int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
990 enum pcep_main_event_type type
, void *payload
)
992 struct pcep_main_event_data
*data
;
994 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
995 data
->handler
= ctrl_state
->main_event_handler
;
997 data
->pcc_id
= pcc_id
;
998 data
->payload
= payload
;
1000 thread_add_event(ctrl_state
->main
, pcep_main_event_handler
,
1001 (void *)data
, 0, NULL
);
1005 int pcep_main_event_handler(struct thread
*thread
)
1007 /* data unpacking */
1008 struct pcep_main_event_data
*data
= THREAD_ARG(thread
);
1009 assert(data
!= NULL
);
1010 pcep_main_event_handler_t handler
= data
->handler
;
1011 enum pcep_main_event_type type
= data
->type
;
1012 int pcc_id
= data
->pcc_id
;
1013 void *payload
= data
->payload
;
1014 XFREE(MTYPE_PCEP
, data
);
1016 return handler(type
, pcc_id
, payload
);
1020 /* ------------ Helper functions ------------ */
1022 void set_ctrl_state(struct frr_pthread
*fpt
, struct ctrl_state
*ctrl_state
)
1024 assert(fpt
!= NULL
);
1025 fpt
->data
= ctrl_state
;
1028 struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
)
1030 assert(fpt
!= NULL
);
1031 assert(fpt
->data
!= NULL
);
1033 struct ctrl_state
*ctrl_state
;
1034 ctrl_state
= (struct ctrl_state
*)fpt
->data
;
1035 assert(ctrl_state
!= NULL
);
1039 int get_next_id(struct ctrl_state
*ctrl_state
)
1041 return ++ctrl_state
->pcc_last_id
;
1044 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
)
1046 assert(ctrl_state
!= NULL
);
1047 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1049 int current_pcc_idx
= pcep_pcc_get_free_pcc_idx(ctrl_state
->pcc
);
1050 if (current_pcc_idx
>= 0) {
1051 ctrl_state
->pcc
[current_pcc_idx
] = pcc_state
;
1052 ctrl_state
->pcc_count
++;
1053 PCEP_DEBUG("added pce pcc_id (%d) idx (%d)",
1054 pcep_pcc_get_pcc_id(pcc_state
), current_pcc_idx
);
1057 PCEP_DEBUG("Max number of pce ");
1062 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
1063 struct pcc_state
*pcc_state
)
1065 assert(ctrl_state
!= NULL
);
1066 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1069 idx
= pcep_pcc_get_pcc_idx_by_id(ctrl_state
->pcc
,
1070 pcep_pcc_get_pcc_id(pcc_state
));
1072 ctrl_state
->pcc
[idx
] = NULL
;
1073 ctrl_state
->pcc_count
--;
1074 PCEP_DEBUG("removed pce pcc_id (%d)",
1075 pcep_pcc_get_pcc_id(pcc_state
));
1079 uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t retry_count
)
1081 uint32_t a
= min(max
, base
* (1 << retry_count
));
1082 uint64_t r
= frr_weak_random(), m
= RAND_MAX
;
1083 uint32_t b
= (a
/ 2) + (r
* (a
/ 2)) / m
;
1087 const char *timer_type_name(enum pcep_ctrl_timer_type type
)
1092 case TM_RECONNECT_PCC
:
1093 return "RECONNECT_PCC";
1094 case TM_PCEPLIB_TIMER
:
1095 return "PCEPLIB_TIMER";
1103 const char *timeout_type_name(enum pcep_ctrl_timeout_type type
)
1108 case TO_COMPUTATION_REQUEST
:
1109 return "COMPUTATION_REQUEST";