1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
12 #include "northbound.h"
13 #include "frr_pthread.h"
17 #include "pathd/pathd.h"
18 #include "pathd/path_errors.h"
19 #include "pathd/path_pcep.h"
20 #include "pathd/path_pcep_controller.h"
21 #include "pathd/path_pcep_pcc.h"
22 #include "pathd/path_pcep_config.h"
23 #include "pathd/path_pcep_debug.h"
25 #define MAX_RECONNECT_DELAY 120
27 /* Event handling data structures */
28 enum pcep_ctrl_event_type
{
29 EV_UPDATE_PCC_OPTS
= 1,
42 struct pcep_ctrl_event_data
{
43 struct ctrl_state
*ctrl_state
;
44 enum pcep_ctrl_event_type type
;
50 struct pcep_main_event_data
{
51 pcep_main_event_handler_t handler
;
53 enum pcep_main_event_type type
;
57 struct pcep_refine_path_event_data
{
58 struct ctrl_state
*ctrl_state
;
60 pcep_refine_callback_t continue_lsp_update_handler
;
65 /* Synchronous call arguments */
67 struct get_counters_args
{
68 struct ctrl_state
*ctrl_state
;
70 struct counters_group
*counters
;
73 struct get_pcep_session_args
{
74 struct ctrl_state
*ctrl_state
;
76 pcep_session
*pcep_session
;
79 /* Internal Functions Called From Main Thread */
80 static int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
);
81 static void pcep_refine_path_event_cb(struct thread
*thread
);
83 /* Internal Functions Called From Controller Thread */
84 static void pcep_thread_finish_event_handler(struct thread
*thread
);
86 /* Controller Thread Timer Handler */
87 static int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
88 enum pcep_ctrl_timer_type timer_type
,
89 enum pcep_ctrl_timeout_type timeout_type
,
90 uint32_t delay
, void *payload
,
91 struct thread
**thread
);
92 static int schedule_thread_timer_with_cb(
93 struct ctrl_state
*ctrl_state
, int pcc_id
,
94 enum pcep_ctrl_timer_type timer_type
,
95 enum pcep_ctrl_timeout_type timeout_type
, uint32_t delay
, void *payload
,
96 struct thread
**thread
, pcep_ctrl_thread_callback timer_cb
);
97 static void pcep_thread_timer_handler(struct thread
*thread
);
99 /* Controller Thread Socket read/write Handler */
100 static int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
101 enum pcep_ctrl_socket_type type
, bool is_read
,
102 void *payload
, int fd
, struct thread
**thread
,
103 pcep_ctrl_thread_callback cb
);
105 /* Controller Thread Event Handler */
106 static int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
107 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
109 static int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
110 enum pcep_ctrl_event_type type
,
111 uint32_t sub_type
, void *payload
,
112 pcep_ctrl_thread_callback event_cb
);
113 static void pcep_thread_event_handler(struct thread
*thread
);
114 static int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
115 struct pcc_opts
*opts
);
116 static int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
118 struct pce_opts
*opts
);
119 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
121 static int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
);
122 static int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
123 struct pce_opts
*pce_opts
);
124 static int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
,
125 int pcc_id
, struct path
*path
);
126 static int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
,
128 static int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
129 enum pcep_pathd_event_type type
,
132 pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
133 struct pcep_refine_path_event_data
*data
);
135 /* Main Thread Event Handler */
136 static int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
137 enum pcep_main_event_type type
, void *payload
);
138 static void pcep_main_event_handler(struct thread
*thread
);
140 /* Helper functions */
141 static void set_ctrl_state(struct frr_pthread
*fpt
,
142 struct ctrl_state
*ctrl_state
);
143 static struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
);
144 int get_next_id(struct ctrl_state
*ctrl_state
);
145 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
);
146 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
147 struct pcc_state
*pcc_state
);
148 static uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t attempt
);
149 static const char *timer_type_name(enum pcep_ctrl_timer_type type
);
150 static const char *timeout_type_name(enum pcep_ctrl_timeout_type type
);
153 /* ------------ API Functions Called from Main Thread ------------ */
155 int pcep_ctrl_initialize(struct thread_master
*main_thread
,
156 struct frr_pthread
**fpt
,
157 pcep_main_event_handler_t event_handler
)
162 struct ctrl_state
*ctrl_state
;
163 struct frr_pthread_attr attr
= {
164 .start
= frr_pthread_attr_default
.start
,
165 .stop
= pcep_ctrl_halt_cb
,
168 PCEP_DEBUG("Initializing pcep module controller");
170 /* Create and start the FRR pthread */
171 *fpt
= frr_pthread_new(&attr
, "PCEP thread", "pcep_controller");
173 flog_err(EC_PATH_SYSTEM_CALL
,
174 "failed to initialize PCEP thread");
177 ret
= frr_pthread_run(*fpt
, NULL
);
179 flog_err(EC_PATH_SYSTEM_CALL
, "failed to create PCEP thread");
182 frr_pthread_wait_running(*fpt
);
184 /* Initialize the thread state */
185 ctrl_state
= XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
));
186 ctrl_state
->main
= main_thread
;
187 ctrl_state
->self
= (*fpt
)->master
;
188 ctrl_state
->main_event_handler
= event_handler
;
189 ctrl_state
->pcc_count
= 0;
190 ctrl_state
->pcc_last_id
= 0;
191 ctrl_state
->pcc_opts
=
192 XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
->pcc_opts
));
193 /* Default to no PCC address defined */
194 ctrl_state
->pcc_opts
->addr
.ipa_type
= IPADDR_NONE
;
195 ctrl_state
->pcc_opts
->port
= PCEP_DEFAULT_PORT
;
197 /* Keep the state reference for events */
198 set_ctrl_state(*fpt
, ctrl_state
);
203 int pcep_ctrl_finalize(struct frr_pthread
**fpt
)
209 PCEP_DEBUG("Finalizing pcep module controller");
212 frr_pthread_stop(*fpt
, NULL
);
219 int pcep_ctrl_update_pcc_options(struct frr_pthread
*fpt
, struct pcc_opts
*opts
)
221 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
222 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCC_OPTS
, 0, opts
);
225 int pcep_ctrl_update_pce_options(struct frr_pthread
*fpt
, struct pce_opts
*opts
)
227 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
228 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCE_OPTS
, 0, opts
);
231 int pcep_ctrl_remove_pcc(struct frr_pthread
*fpt
, struct pce_opts
*pce_opts
)
233 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
234 return send_to_thread(ctrl_state
, 0, EV_REMOVE_PCC
, 0, pce_opts
);
237 int pcep_ctrl_reset_pcc_session(struct frr_pthread
*fpt
, char *pce_name
)
239 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
240 return send_to_thread(ctrl_state
, 0, EV_RESET_PCC_SESSION
, 0, pce_name
);
243 int pcep_ctrl_pathd_event(struct frr_pthread
*fpt
,
244 enum pcep_pathd_event_type type
, struct path
*path
)
246 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
247 return send_to_thread(ctrl_state
, 0, EV_PATHD_EVENT
, type
, path
);
250 int pcep_ctrl_sync_path(struct frr_pthread
*fpt
, int pcc_id
, struct path
*path
)
252 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
253 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_PATH
, 0, path
);
256 int pcep_ctrl_sync_done(struct frr_pthread
*fpt
, int pcc_id
)
258 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
259 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_DONE
, 0, NULL
);
262 struct counters_group
*pcep_ctrl_get_counters(struct frr_pthread
*fpt
,
265 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
266 struct counters_group
*counters
= NULL
;
267 struct pcc_state
*pcc_state
;
268 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
270 counters
= pcep_lib_copy_counters(pcc_state
->sess
);
275 pcep_session
*pcep_ctrl_get_pcep_session(struct frr_pthread
*fpt
, int pcc_id
)
277 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
278 struct pcc_state
*pcc_state
;
279 pcep_session
*session
= NULL
;
281 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
283 session
= pcep_lib_copy_pcep_session(pcc_state
->sess
);
288 struct pcep_pcc_info
*pcep_ctrl_get_pcc_info(struct frr_pthread
*fpt
,
289 const char *pce_name
)
291 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
292 struct pcep_pcc_info
*pcc_info
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_info
));
293 if( pcc_info
&& ctrl_state
){
294 strlcpy(pcc_info
->pce_name
, pce_name
, sizeof(pcc_info
->pce_name
));
295 pcep_pcc_copy_pcc_info(ctrl_state
->pcc
, pcc_info
);
301 int pcep_ctrl_send_report(struct frr_pthread
*fpt
, int pcc_id
,
302 struct path
*path
, bool is_stable
)
304 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
305 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_REPORT
, is_stable
,
310 int pcep_ctrl_send_error(struct frr_pthread
*fpt
, int pcc_id
,
311 struct pcep_error
*error
)
313 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
314 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_ERROR
, 0, error
);
318 /* ------------ Internal Functions Called from Main Thread ------------ */
320 int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
)
322 thread_add_event(fpt
->master
, pcep_thread_finish_event_handler
,
323 (void *)fpt
, 0, NULL
);
324 pthread_join(fpt
->thread
, res
);
329 void pcep_refine_path_event_cb(struct thread
*thread
)
331 struct pcep_refine_path_event_data
*data
= THREAD_ARG(thread
);
332 assert(data
!= NULL
);
333 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
334 struct path
*path
= data
->path
;
335 assert(path
!= NULL
);
336 int pcc_id
= data
->pcc_id
;
339 path_pcep_refine_path(path
);
340 send_to_thread(ctrl_state
, pcc_id
, EV_PATH_REFINED
, 0, data
);
344 /* ------------ API Functions Called From Controller Thread ------------ */
346 void pcep_thread_start_sync(struct ctrl_state
*ctrl_state
, int pcc_id
)
348 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_START_SYNC
, NULL
);
351 void pcep_thread_update_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
354 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_UPDATE_CANDIDATE
,
358 void pcep_thread_initiate_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
361 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_INITIATE_CANDIDATE
,
365 void pcep_thread_remove_candidate_path_segments(struct ctrl_state
*ctrl_state
,
366 struct pcc_state
*pcc_state
)
370 /* Will be deleted when the event is handled */
371 char *originator
= XSTRDUP(MTYPE_PCEP
, pcc_state
->originator
);
372 PCEP_DEBUG("schedule candidate path segments removal for originator %s",
374 send_to_main(ctrl_state
, pcep_pcc_get_pcc_id(pcc_state
),
375 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
, originator
);
378 void pcep_thread_schedule_sync_best_pce(struct ctrl_state
*ctrl_state
,
379 int pcc_id
, int delay
,
380 struct thread
**thread
)
383 schedule_thread_timer(ctrl_state
, pcc_id
, TM_CALCULATE_BEST_PCE
,
384 TO_UNDEFINED
, delay
, NULL
, thread
);
387 void pcep_thread_cancel_timer(struct thread
**thread
)
389 if (thread
== NULL
|| *thread
== NULL
) {
393 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(*thread
);
394 PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data
->timer_type
),
395 timeout_type_name(data
->timeout_type
));
397 XFREE(MTYPE_PCEP
, data
);
400 if ((*thread
)->master
->owner
== pthread_self()) {
401 thread_cancel(thread
);
403 thread_cancel_async((*thread
)->master
, thread
, NULL
);
407 void pcep_thread_schedule_reconnect(struct ctrl_state
*ctrl_state
, int pcc_id
,
408 int retry_count
, struct thread
**thread
)
410 uint32_t delay
= backoff_delay(MAX_RECONNECT_DELAY
, 1, retry_count
);
411 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay
,
413 schedule_thread_timer(ctrl_state
, pcc_id
, TM_RECONNECT_PCC
,
414 TO_UNDEFINED
, delay
, NULL
, thread
);
417 void pcep_thread_schedule_timeout(struct ctrl_state
*ctrl_state
, int pcc_id
,
418 enum pcep_ctrl_timeout_type timeout_type
,
419 uint32_t delay
, void *param
,
420 struct thread
**thread
)
422 assert(timeout_type
> TO_UNDEFINED
);
423 assert(timeout_type
< TO_MAX
);
424 PCEP_DEBUG("Schedule timeout %s for %us",
425 timeout_type_name(timeout_type
), delay
);
426 schedule_thread_timer(ctrl_state
, pcc_id
, TM_TIMEOUT
, timeout_type
,
427 delay
, param
, thread
);
430 void pcep_thread_schedule_pceplib_timer(struct ctrl_state
*ctrl_state
,
431 int delay
, void *payload
,
432 struct thread
**thread
,
433 pcep_ctrl_thread_callback timer_cb
)
435 PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay
);
436 schedule_thread_timer_with_cb(ctrl_state
, 0, TM_PCEPLIB_TIMER
,
437 TO_UNDEFINED
, delay
, payload
, thread
,
441 void pcep_thread_schedule_session_timeout(struct ctrl_state
*ctrl_state
,
442 int pcc_id
, int delay
,
443 struct thread
**thread
)
445 PCEP_DEBUG("Schedule session_timeout interval for %us", delay
);
446 schedule_thread_timer(ctrl_state
, pcc_id
, TM_SESSION_TIMEOUT_PCC
,
447 TO_UNDEFINED
, delay
, NULL
, thread
);
450 int pcep_thread_pcc_count(struct ctrl_state
*ctrl_state
)
452 if (ctrl_state
== NULL
) {
456 return ctrl_state
->pcc_count
;
459 int pcep_thread_refine_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
460 pcep_refine_callback_t cb
, struct path
*path
,
463 struct pcep_refine_path_event_data
*data
;
465 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
466 data
->ctrl_state
= ctrl_state
;
468 data
->pcc_id
= pcc_id
;
469 data
->continue_lsp_update_handler
= cb
;
470 data
->payload
= payload
;
472 thread_add_event(ctrl_state
->main
, pcep_refine_path_event_cb
,
473 (void *)data
, 0, NULL
);
477 void pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
478 struct pcep_refine_path_event_data
*data
)
480 assert(data
!= NULL
);
481 int pcc_id
= data
->pcc_id
;
482 pcep_refine_callback_t continue_lsp_update_handler
= data
->continue_lsp_update_handler
;
483 assert(continue_lsp_update_handler
!= NULL
);
484 struct path
*path
= data
->path
;
485 void *payload
= data
->payload
;
486 struct pcc_state
*pcc_state
= NULL
;
487 XFREE(MTYPE_PCEP
, data
);
489 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
490 continue_lsp_update_handler(ctrl_state
, pcc_state
, path
, payload
);
494 /* ------------ Internal Functions Called From Controller Thread ------------ */
496 void pcep_thread_finish_event_handler(struct thread
*thread
)
499 struct frr_pthread
*fpt
= THREAD_ARG(thread
);
500 struct ctrl_state
*ctrl_state
= fpt
->data
;
502 assert(ctrl_state
!= NULL
);
504 for (i
= 0; i
< MAX_PCC
; i
++) {
505 if (ctrl_state
->pcc
[i
]) {
506 pcep_pcc_finalize(ctrl_state
, ctrl_state
->pcc
[i
]);
507 ctrl_state
->pcc
[i
] = NULL
;
511 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
512 XFREE(MTYPE_PCEP
, ctrl_state
);
515 atomic_store_explicit(&fpt
->running
, false, memory_order_relaxed
);
518 /* ------------ Controller Thread Timer Handler ------------ */
520 int schedule_thread_timer_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
521 enum pcep_ctrl_timer_type timer_type
,
522 enum pcep_ctrl_timeout_type timeout_type
,
523 uint32_t delay
, void *payload
,
524 struct thread
**thread
,
525 pcep_ctrl_thread_callback timer_cb
)
527 assert(thread
!= NULL
);
529 struct pcep_ctrl_timer_data
*data
;
531 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
532 data
->ctrl_state
= ctrl_state
;
533 data
->timer_type
= timer_type
;
534 data
->timeout_type
= timeout_type
;
535 data
->pcc_id
= pcc_id
;
536 data
->payload
= payload
;
538 thread_add_timer(ctrl_state
->self
, timer_cb
, (void *)data
, delay
,
544 int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
545 enum pcep_ctrl_timer_type timer_type
,
546 enum pcep_ctrl_timeout_type timeout_type
,
547 uint32_t delay
, void *payload
, struct thread
**thread
)
549 return schedule_thread_timer_with_cb(ctrl_state
, pcc_id
, timer_type
,
550 timeout_type
, delay
, payload
,
551 thread
, pcep_thread_timer_handler
);
554 void pcep_thread_timer_handler(struct thread
*thread
)
557 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(thread
);
558 assert(data
!= NULL
);
559 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
560 assert(ctrl_state
!= NULL
);
561 enum pcep_ctrl_timer_type timer_type
= data
->timer_type
;
562 enum pcep_ctrl_timeout_type timeout_type
= data
->timeout_type
;
563 int pcc_id
= data
->pcc_id
;
564 void *param
= data
->payload
;
565 XFREE(MTYPE_PCEP
, data
);
567 struct pcc_state
*pcc_state
= NULL
;
569 switch (timer_type
) {
570 case TM_RECONNECT_PCC
:
571 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
574 pcep_pcc_reconnect(ctrl_state
, pcc_state
);
577 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
580 pcep_pcc_timeout_handler(ctrl_state
, pcc_state
, timeout_type
,
583 case TM_CALCULATE_BEST_PCE
:
584 /* Previous best disconnect so new best should be synced */
585 pcep_pcc_timer_update_best_pce(ctrl_state
, pcc_id
);
587 case TM_SESSION_TIMEOUT_PCC
:
588 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
589 pcep_thread_remove_candidate_path_segments(ctrl_state
,
592 case TM_PCEPLIB_TIMER
:
595 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
596 "Unknown controller timer triggered: %u", timer_type
);
601 void pcep_thread_pcep_event(struct thread
*thread
)
603 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
604 assert(data
!= NULL
);
605 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
606 pcep_event
*event
= data
->payload
;
607 XFREE(MTYPE_PCEP
, data
);
610 for (i
= 0; i
< MAX_PCC
; i
++) {
611 if (ctrl_state
->pcc
[i
]) {
612 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
613 if (pcc_state
->sess
!= event
->session
)
615 pcep_pcc_pcep_event_handler(ctrl_state
, pcc_state
,
620 destroy_pcep_event(event
);
623 /* ------------ Controller Thread Socket Functions ------------ */
625 int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
626 enum pcep_ctrl_socket_type type
, bool is_read
,
627 void *payload
, int fd
, struct thread
**thread
,
628 pcep_ctrl_thread_callback socket_cb
)
630 assert(thread
!= NULL
);
632 struct pcep_ctrl_socket_data
*data
;
634 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
635 data
->ctrl_state
= ctrl_state
;
637 data
->is_read
= is_read
;
639 data
->pcc_id
= pcc_id
;
640 data
->payload
= payload
;
643 thread_add_read(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
646 thread_add_write(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
653 int pcep_thread_socket_write(void *fpt
, void **thread
, int fd
, void *payload
,
654 pcep_ctrl_thread_callback socket_cb
)
656 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
658 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, false,
659 payload
, fd
, (struct thread
**)thread
,
663 int pcep_thread_socket_read(void *fpt
, void **thread
, int fd
, void *payload
,
664 pcep_ctrl_thread_callback socket_cb
)
666 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
668 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, true,
669 payload
, fd
, (struct thread
**)thread
,
673 int pcep_thread_send_ctrl_event(void *fpt
, void *payload
,
674 pcep_ctrl_thread_callback cb
)
676 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
678 return send_to_thread_with_cb(ctrl_state
, 0, EV_PCEPLIB_EVENT
, 0,
682 /* ------------ Controller Thread Event Handler ------------ */
684 int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
685 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
688 return send_to_thread_with_cb(ctrl_state
, pcc_id
, type
, sub_type
,
689 payload
, pcep_thread_event_handler
);
692 int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
693 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
694 void *payload
, pcep_ctrl_thread_callback event_cb
)
696 struct pcep_ctrl_event_data
*data
;
698 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
699 data
->ctrl_state
= ctrl_state
;
701 data
->sub_type
= sub_type
;
702 data
->pcc_id
= pcc_id
;
703 data
->payload
= payload
;
705 thread_add_event(ctrl_state
->self
, event_cb
, (void *)data
, 0, NULL
);
710 void pcep_thread_event_handler(struct thread
*thread
)
713 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
714 assert(data
!= NULL
);
715 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
716 assert(ctrl_state
!= NULL
);
717 enum pcep_ctrl_event_type type
= data
->type
;
718 uint32_t sub_type
= data
->sub_type
;
719 int pcc_id
= data
->pcc_id
;
720 void *payload
= data
->payload
;
721 XFREE(MTYPE_PCEP
, data
);
723 /* Possible sub-type values */
724 enum pcep_pathd_event_type path_event_type
= PCEP_PATH_UNDEFINED
;
726 /* Possible payload values, maybe an union would be better... */
727 struct path
*path
= NULL
;
728 struct pcc_opts
*pcc_opts
= NULL
;
729 struct pce_opts
*pce_opts
= NULL
;
730 struct pcc_state
*pcc_state
= NULL
;
731 struct pcep_refine_path_event_data
*refine_data
= NULL
;
733 struct path
*path_copy
= NULL
;
734 struct pcep_error
*error
= NULL
;
737 case EV_UPDATE_PCC_OPTS
:
738 assert(payload
!= NULL
);
739 pcc_opts
= (struct pcc_opts
*)payload
;
740 pcep_thread_event_update_pcc_options(ctrl_state
, pcc_opts
);
742 case EV_UPDATE_PCE_OPTS
:
743 assert(payload
!= NULL
);
744 pce_opts
= (struct pce_opts
*)payload
;
745 pcep_thread_event_update_pce_options(ctrl_state
, pcc_id
,
749 pce_opts
= (struct pce_opts
*)payload
;
750 if (pcep_thread_event_remove_pcc(ctrl_state
, pce_opts
) == 0)
751 pcep_pcc_multi_pce_remove_pcc(ctrl_state
,
755 assert(payload
!= NULL
);
756 path_event_type
= (enum pcep_pathd_event_type
)sub_type
;
757 path
= (struct path
*)payload
;
758 pcep_thread_event_pathd_event(ctrl_state
, path_event_type
,
762 assert(payload
!= NULL
);
763 path
= (struct path
*)payload
;
764 pcep_pcc_multi_pce_sync_path(ctrl_state
, pcc_id
,
766 pcep_thread_event_sync_path(ctrl_state
, pcc_id
, path
);
769 pcep_thread_event_sync_done(ctrl_state
, pcc_id
);
771 case EV_RESET_PCC_SESSION
:
772 pcc_state
= pcep_pcc_get_pcc_by_name(ctrl_state
->pcc
,
773 (const char *)payload
);
775 pcep_pcc_disable(ctrl_state
, pcc_state
);
776 pcep_pcc_enable(ctrl_state
, pcc_state
);
778 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
779 "Cannot reset state for PCE: %s",
780 (const char *)payload
);
784 assert(payload
!= NULL
);
785 path
= (struct path
*)payload
;
787 for (int i
= 0; i
< MAX_PCC
; i
++) {
788 if (ctrl_state
->pcc
[i
]) {
789 path_copy
= pcep_copy_path(path
);
790 pcep_pcc_send_report(
791 ctrl_state
, ctrl_state
->pcc
[i
],
792 path_copy
, (bool)sub_type
);
797 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
798 pcep_pcc_send_report(ctrl_state
, pcc_state
, path
,
802 case EV_PATH_REFINED
:
803 assert(payload
!= NULL
);
804 refine_data
= (struct pcep_refine_path_event_data
*)payload
;
805 pcep_thread_path_refined_event(ctrl_state
, refine_data
);
808 assert(payload
!= NULL
);
809 error
= (struct pcep_error
*)payload
;
810 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
811 pcep_pcc_send_error(ctrl_state
, pcc_state
, error
,
814 case EV_PCEPLIB_EVENT
:
815 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
816 "Unexpected event received in controller thread: %u",
822 int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
823 struct pcc_opts
*opts
)
825 assert(opts
!= NULL
);
826 if (ctrl_state
->pcc_opts
!= NULL
) {
827 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
829 ctrl_state
->pcc_opts
= opts
;
833 int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
834 int pcc_id
, struct pce_opts
*pce_opts
)
836 if (!pce_opts
|| !ctrl_state
) {
839 struct pcc_state
*pcc_state
;
840 struct pcc_opts
*pcc_opts
;
843 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
, pce_opts
);
844 if (current_pcc_id
) {
846 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, current_pcc_id
);
848 pcc_state
= pcep_pcc_initialize(ctrl_state
,
849 get_next_id(ctrl_state
));
850 if (set_pcc_state(ctrl_state
, pcc_state
)) {
851 XFREE(MTYPE_PCEP
, pcc_state
);
856 /* Copy the pcc options to delegate it to the update function */
857 pcc_opts
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_opts
));
858 memcpy(pcc_opts
, ctrl_state
->pcc_opts
, sizeof(*pcc_opts
));
860 if (pcep_pcc_update(ctrl_state
, pcc_state
, pcc_opts
, pce_opts
)) {
861 flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE
,
862 "failed to update PCC configuration");
869 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
873 struct pcc_state
*pcc_state
=
874 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
876 remove_pcc_state(ctrl_state
, pcc_state
);
877 pcep_pcc_finalize(ctrl_state
, pcc_state
);
883 int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
)
885 assert(ctrl_state
!= NULL
);
887 for (int i
= 0; i
< MAX_PCC
; i
++) {
888 pcep_thread_event_remove_pcc_by_id(
890 pcep_pcc_get_pcc_id_by_idx(ctrl_state
->pcc
, i
));
895 int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
896 struct pce_opts
*pce_opts
)
898 assert(ctrl_state
!= NULL
);
901 int pcc_id
= pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
,
904 pcep_thread_event_remove_pcc_by_id(ctrl_state
, pcc_id
);
908 XFREE(MTYPE_PCEP
, pce_opts
);
910 pcep_thread_event_remove_pcc_all(ctrl_state
);
916 int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
919 struct pcc_state
*pcc_state
=
920 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
921 pcep_pcc_sync_path(ctrl_state
, pcc_state
, path
);
922 pcep_free_path(path
);
926 int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
, int pcc_id
)
928 struct pcc_state
*pcc_state
=
929 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
930 pcep_pcc_sync_done(ctrl_state
, pcc_state
);
934 int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
935 enum pcep_pathd_event_type type
,
940 for (i
= 0; i
< MAX_PCC
; i
++) {
941 if (ctrl_state
->pcc
[i
]) {
942 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
943 pcep_pcc_pathd_event_handler(ctrl_state
, pcc_state
,
948 pcep_free_path(path
);
954 /* ------------ Main Thread Event Handler ------------ */
956 int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
957 enum pcep_main_event_type type
, void *payload
)
959 struct pcep_main_event_data
*data
;
961 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
962 data
->handler
= ctrl_state
->main_event_handler
;
964 data
->pcc_id
= pcc_id
;
965 data
->payload
= payload
;
967 thread_add_event(ctrl_state
->main
, pcep_main_event_handler
,
968 (void *)data
, 0, NULL
);
972 void pcep_main_event_handler(struct thread
*thread
)
975 struct pcep_main_event_data
*data
= THREAD_ARG(thread
);
976 assert(data
!= NULL
);
977 pcep_main_event_handler_t handler
= data
->handler
;
978 enum pcep_main_event_type type
= data
->type
;
979 int pcc_id
= data
->pcc_id
;
980 void *payload
= data
->payload
;
981 XFREE(MTYPE_PCEP
, data
);
983 handler(type
, pcc_id
, payload
);
987 /* ------------ Helper functions ------------ */
989 void set_ctrl_state(struct frr_pthread
*fpt
, struct ctrl_state
*ctrl_state
)
992 fpt
->data
= ctrl_state
;
995 struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
)
998 assert(fpt
->data
!= NULL
);
1000 struct ctrl_state
*ctrl_state
;
1001 ctrl_state
= (struct ctrl_state
*)fpt
->data
;
1002 assert(ctrl_state
!= NULL
);
1006 int get_next_id(struct ctrl_state
*ctrl_state
)
1008 return ++ctrl_state
->pcc_last_id
;
1011 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
)
1013 assert(ctrl_state
!= NULL
);
1014 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1016 int current_pcc_idx
= pcep_pcc_get_free_pcc_idx(ctrl_state
->pcc
);
1017 if (current_pcc_idx
>= 0) {
1018 ctrl_state
->pcc
[current_pcc_idx
] = pcc_state
;
1019 ctrl_state
->pcc_count
++;
1020 PCEP_DEBUG("added pce pcc_id (%d) idx (%d)",
1021 pcep_pcc_get_pcc_id(pcc_state
), current_pcc_idx
);
1024 PCEP_DEBUG("Max number of pce ");
1029 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
1030 struct pcc_state
*pcc_state
)
1032 assert(ctrl_state
!= NULL
);
1033 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1036 idx
= pcep_pcc_get_pcc_idx_by_id(ctrl_state
->pcc
,
1037 pcep_pcc_get_pcc_id(pcc_state
));
1039 ctrl_state
->pcc
[idx
] = NULL
;
1040 ctrl_state
->pcc_count
--;
1041 PCEP_DEBUG("removed pce pcc_id (%d)",
1042 pcep_pcc_get_pcc_id(pcc_state
));
1046 uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t retry_count
)
1048 uint32_t a
= MIN(max
, base
* (1 << retry_count
));
1049 uint64_t r
= frr_weak_random(), m
= RAND_MAX
;
1050 uint32_t b
= (a
/ 2) + (r
* (a
/ 2)) / m
;
1054 const char *timer_type_name(enum pcep_ctrl_timer_type type
)
1059 case TM_RECONNECT_PCC
:
1060 return "RECONNECT_PCC";
1061 case TM_PCEPLIB_TIMER
:
1062 return "PCEPLIB_TIMER";
1065 case TM_CALCULATE_BEST_PCE
:
1067 case TM_SESSION_TIMEOUT_PCC
:
1068 return "TIMEOUT_PCC";
1073 assert(!"Reached end of function where we did not expect to");
1076 const char *timeout_type_name(enum pcep_ctrl_timeout_type type
)
1081 case TO_COMPUTATION_REQUEST
:
1082 return "COMPUTATION_REQUEST";
1087 assert(!"Reached end of function where we did not expect to");