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 "northbound.h"
26 #include "frr_pthread.h"
30 #include "pathd/pathd.h"
31 #include "pathd/path_errors.h"
32 #include "pathd/path_pcep.h"
33 #include "pathd/path_pcep_controller.h"
34 #include "pathd/path_pcep_pcc.h"
35 #include "pathd/path_pcep_config.h"
36 #include "pathd/path_pcep_debug.h"
38 #define MAX_RECONNECT_DELAY 120
40 /* Event handling data structures */
41 enum pcep_ctrl_event_type
{
42 EV_UPDATE_PCC_OPTS
= 1,
55 struct pcep_ctrl_event_data
{
56 struct ctrl_state
*ctrl_state
;
57 enum pcep_ctrl_event_type type
;
63 struct pcep_main_event_data
{
64 pcep_main_event_handler_t handler
;
66 enum pcep_main_event_type type
;
70 struct pcep_refine_path_event_data
{
71 struct ctrl_state
*ctrl_state
;
73 pcep_refine_callback_t continue_lsp_update_handler
;
78 /* Synchronous call arguments */
80 struct get_counters_args
{
81 struct ctrl_state
*ctrl_state
;
83 struct counters_group
*counters
;
86 struct get_pcep_session_args
{
87 struct ctrl_state
*ctrl_state
;
89 pcep_session
*pcep_session
;
92 /* Internal Functions Called From Main Thread */
93 static int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
);
94 static void pcep_refine_path_event_cb(struct thread
*thread
);
96 /* Internal Functions Called From Controller Thread */
97 static void pcep_thread_finish_event_handler(struct thread
*thread
);
99 /* Controller Thread Timer Handler */
100 static int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
101 enum pcep_ctrl_timer_type timer_type
,
102 enum pcep_ctrl_timeout_type timeout_type
,
103 uint32_t delay
, void *payload
,
104 struct thread
**thread
);
105 static int schedule_thread_timer_with_cb(
106 struct ctrl_state
*ctrl_state
, int pcc_id
,
107 enum pcep_ctrl_timer_type timer_type
,
108 enum pcep_ctrl_timeout_type timeout_type
, uint32_t delay
, void *payload
,
109 struct thread
**thread
, pcep_ctrl_thread_callback timer_cb
);
110 static void pcep_thread_timer_handler(struct thread
*thread
);
112 /* Controller Thread Socket read/write Handler */
113 static int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
114 enum pcep_ctrl_socket_type type
, bool is_read
,
115 void *payload
, int fd
, struct thread
**thread
,
116 pcep_ctrl_thread_callback cb
);
118 /* Controller Thread Event Handler */
119 static int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
120 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
122 static int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
123 enum pcep_ctrl_event_type type
,
124 uint32_t sub_type
, void *payload
,
125 pcep_ctrl_thread_callback event_cb
);
126 static void pcep_thread_event_handler(struct thread
*thread
);
127 static int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
128 struct pcc_opts
*opts
);
129 static int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
131 struct pce_opts
*opts
);
132 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
134 static int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
);
135 static int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
136 struct pce_opts
*pce_opts
);
137 static int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
,
138 int pcc_id
, struct path
*path
);
139 static int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
,
141 static int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
142 enum pcep_pathd_event_type type
,
145 pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
146 struct pcep_refine_path_event_data
*data
);
148 /* Main Thread Event Handler */
149 static int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
150 enum pcep_main_event_type type
, void *payload
);
151 static void pcep_main_event_handler(struct thread
*thread
);
153 /* Helper functions */
154 static void set_ctrl_state(struct frr_pthread
*fpt
,
155 struct ctrl_state
*ctrl_state
);
156 static struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
);
157 int get_next_id(struct ctrl_state
*ctrl_state
);
158 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
);
159 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
160 struct pcc_state
*pcc_state
);
161 static uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t attempt
);
162 static const char *timer_type_name(enum pcep_ctrl_timer_type type
);
163 static const char *timeout_type_name(enum pcep_ctrl_timeout_type type
);
166 /* ------------ API Functions Called from Main Thread ------------ */
168 int pcep_ctrl_initialize(struct thread_master
*main_thread
,
169 struct frr_pthread
**fpt
,
170 pcep_main_event_handler_t event_handler
)
175 struct ctrl_state
*ctrl_state
;
176 struct frr_pthread_attr attr
= {
177 .start
= frr_pthread_attr_default
.start
,
178 .stop
= pcep_ctrl_halt_cb
,
181 PCEP_DEBUG("Initializing pcep module controller");
183 /* Create and start the FRR pthread */
184 *fpt
= frr_pthread_new(&attr
, "PCEP thread", "pcep_controller");
186 flog_err(EC_PATH_SYSTEM_CALL
,
187 "failed to initialize PCEP thread");
190 ret
= frr_pthread_run(*fpt
, NULL
);
192 flog_err(EC_PATH_SYSTEM_CALL
, "failed to create PCEP thread");
195 frr_pthread_wait_running(*fpt
);
197 /* Initialize the thread state */
198 ctrl_state
= XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
));
199 ctrl_state
->main
= main_thread
;
200 ctrl_state
->self
= (*fpt
)->master
;
201 ctrl_state
->main_event_handler
= event_handler
;
202 ctrl_state
->pcc_count
= 0;
203 ctrl_state
->pcc_last_id
= 0;
204 ctrl_state
->pcc_opts
=
205 XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
->pcc_opts
));
206 /* Default to no PCC address defined */
207 ctrl_state
->pcc_opts
->addr
.ipa_type
= IPADDR_NONE
;
208 ctrl_state
->pcc_opts
->port
= PCEP_DEFAULT_PORT
;
210 /* Keep the state reference for events */
211 set_ctrl_state(*fpt
, ctrl_state
);
216 int pcep_ctrl_finalize(struct frr_pthread
**fpt
)
222 PCEP_DEBUG("Finalizing pcep module controller");
225 frr_pthread_stop(*fpt
, NULL
);
232 int pcep_ctrl_update_pcc_options(struct frr_pthread
*fpt
, struct pcc_opts
*opts
)
234 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
235 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCC_OPTS
, 0, opts
);
238 int pcep_ctrl_update_pce_options(struct frr_pthread
*fpt
, struct pce_opts
*opts
)
240 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
241 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCE_OPTS
, 0, opts
);
244 int pcep_ctrl_remove_pcc(struct frr_pthread
*fpt
, struct pce_opts
*pce_opts
)
246 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
247 return send_to_thread(ctrl_state
, 0, EV_REMOVE_PCC
, 0, pce_opts
);
250 int pcep_ctrl_reset_pcc_session(struct frr_pthread
*fpt
, char *pce_name
)
252 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
253 return send_to_thread(ctrl_state
, 0, EV_RESET_PCC_SESSION
, 0, pce_name
);
256 int pcep_ctrl_pathd_event(struct frr_pthread
*fpt
,
257 enum pcep_pathd_event_type type
, struct path
*path
)
259 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
260 return send_to_thread(ctrl_state
, 0, EV_PATHD_EVENT
, type
, path
);
263 int pcep_ctrl_sync_path(struct frr_pthread
*fpt
, int pcc_id
, struct path
*path
)
265 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
266 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_PATH
, 0, path
);
269 int pcep_ctrl_sync_done(struct frr_pthread
*fpt
, int pcc_id
)
271 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
272 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_DONE
, 0, NULL
);
275 struct counters_group
*pcep_ctrl_get_counters(struct frr_pthread
*fpt
,
278 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
279 struct counters_group
*counters
= NULL
;
280 struct pcc_state
*pcc_state
;
281 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
283 counters
= pcep_lib_copy_counters(pcc_state
->sess
);
288 pcep_session
*pcep_ctrl_get_pcep_session(struct frr_pthread
*fpt
, int pcc_id
)
290 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
291 struct pcc_state
*pcc_state
;
292 pcep_session
*session
= NULL
;
294 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
296 session
= pcep_lib_copy_pcep_session(pcc_state
->sess
);
301 struct pcep_pcc_info
*pcep_ctrl_get_pcc_info(struct frr_pthread
*fpt
,
302 const char *pce_name
)
304 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
305 struct pcep_pcc_info
*pcc_info
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_info
));
306 if( pcc_info
&& ctrl_state
){
307 strlcpy(pcc_info
->pce_name
, pce_name
, sizeof(pcc_info
->pce_name
));
308 pcep_pcc_copy_pcc_info(ctrl_state
->pcc
, pcc_info
);
314 int pcep_ctrl_send_report(struct frr_pthread
*fpt
, int pcc_id
,
315 struct path
*path
, bool is_stable
)
317 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
318 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_REPORT
, is_stable
,
323 int pcep_ctrl_send_error(struct frr_pthread
*fpt
, int pcc_id
,
324 struct pcep_error
*error
)
326 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
327 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_ERROR
, 0, error
);
331 /* ------------ Internal Functions Called from Main Thread ------------ */
333 int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
)
335 thread_add_event(fpt
->master
, pcep_thread_finish_event_handler
,
336 (void *)fpt
, 0, NULL
);
337 pthread_join(fpt
->thread
, res
);
342 void pcep_refine_path_event_cb(struct thread
*thread
)
344 struct pcep_refine_path_event_data
*data
= THREAD_ARG(thread
);
345 assert(data
!= NULL
);
346 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
347 struct path
*path
= data
->path
;
348 assert(path
!= NULL
);
349 int pcc_id
= data
->pcc_id
;
352 path_pcep_refine_path(path
);
353 send_to_thread(ctrl_state
, pcc_id
, EV_PATH_REFINED
, 0, data
);
357 /* ------------ API Functions Called From Controller Thread ------------ */
359 void pcep_thread_start_sync(struct ctrl_state
*ctrl_state
, int pcc_id
)
361 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_START_SYNC
, NULL
);
364 void pcep_thread_update_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
367 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_UPDATE_CANDIDATE
,
371 void pcep_thread_initiate_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
374 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_INITIATE_CANDIDATE
,
378 void pcep_thread_remove_candidate_path_segments(struct ctrl_state
*ctrl_state
,
379 struct pcc_state
*pcc_state
)
383 /* Will be deleted when the event is handled */
384 char *originator
= XSTRDUP(MTYPE_PCEP
, pcc_state
->originator
);
385 PCEP_DEBUG("schedule candidate path segments removal for originator %s",
387 send_to_main(ctrl_state
, pcep_pcc_get_pcc_id(pcc_state
),
388 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
, originator
);
391 void pcep_thread_schedule_sync_best_pce(struct ctrl_state
*ctrl_state
,
392 int pcc_id
, int delay
,
393 struct thread
**thread
)
396 schedule_thread_timer(ctrl_state
, pcc_id
, TM_CALCULATE_BEST_PCE
,
397 TO_UNDEFINED
, delay
, NULL
, thread
);
400 void pcep_thread_cancel_timer(struct thread
**thread
)
402 if (thread
== NULL
|| *thread
== NULL
) {
406 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(*thread
);
407 PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data
->timer_type
),
408 timeout_type_name(data
->timeout_type
));
410 XFREE(MTYPE_PCEP
, data
);
413 if ((*thread
)->master
->owner
== pthread_self()) {
414 thread_cancel(thread
);
416 thread_cancel_async((*thread
)->master
, thread
, NULL
);
420 void pcep_thread_schedule_reconnect(struct ctrl_state
*ctrl_state
, int pcc_id
,
421 int retry_count
, struct thread
**thread
)
423 uint32_t delay
= backoff_delay(MAX_RECONNECT_DELAY
, 1, retry_count
);
424 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay
,
426 schedule_thread_timer(ctrl_state
, pcc_id
, TM_RECONNECT_PCC
,
427 TO_UNDEFINED
, delay
, NULL
, thread
);
430 void pcep_thread_schedule_timeout(struct ctrl_state
*ctrl_state
, int pcc_id
,
431 enum pcep_ctrl_timeout_type timeout_type
,
432 uint32_t delay
, void *param
,
433 struct thread
**thread
)
435 assert(timeout_type
> TO_UNDEFINED
);
436 assert(timeout_type
< TO_MAX
);
437 PCEP_DEBUG("Schedule timeout %s for %us",
438 timeout_type_name(timeout_type
), delay
);
439 schedule_thread_timer(ctrl_state
, pcc_id
, TM_TIMEOUT
, timeout_type
,
440 delay
, param
, thread
);
443 void pcep_thread_schedule_pceplib_timer(struct ctrl_state
*ctrl_state
,
444 int delay
, void *payload
,
445 struct thread
**thread
,
446 pcep_ctrl_thread_callback timer_cb
)
448 PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay
);
449 schedule_thread_timer_with_cb(ctrl_state
, 0, TM_PCEPLIB_TIMER
,
450 TO_UNDEFINED
, delay
, payload
, thread
,
454 void pcep_thread_schedule_session_timeout(struct ctrl_state
*ctrl_state
,
455 int pcc_id
, int delay
,
456 struct thread
**thread
)
458 PCEP_DEBUG("Schedule session_timeout interval for %us", delay
);
459 schedule_thread_timer(ctrl_state
, pcc_id
, TM_SESSION_TIMEOUT_PCC
,
460 TO_UNDEFINED
, delay
, NULL
, thread
);
463 int pcep_thread_pcc_count(struct ctrl_state
*ctrl_state
)
465 if (ctrl_state
== NULL
) {
469 return ctrl_state
->pcc_count
;
472 int pcep_thread_refine_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
473 pcep_refine_callback_t cb
, struct path
*path
,
476 struct pcep_refine_path_event_data
*data
;
478 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
479 data
->ctrl_state
= ctrl_state
;
481 data
->pcc_id
= pcc_id
;
482 data
->continue_lsp_update_handler
= cb
;
483 data
->payload
= payload
;
485 thread_add_event(ctrl_state
->main
, pcep_refine_path_event_cb
,
486 (void *)data
, 0, NULL
);
490 void pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
491 struct pcep_refine_path_event_data
*data
)
493 assert(data
!= NULL
);
494 int pcc_id
= data
->pcc_id
;
495 pcep_refine_callback_t continue_lsp_update_handler
= data
->continue_lsp_update_handler
;
496 assert(continue_lsp_update_handler
!= NULL
);
497 struct path
*path
= data
->path
;
498 void *payload
= data
->payload
;
499 struct pcc_state
*pcc_state
= NULL
;
500 XFREE(MTYPE_PCEP
, data
);
502 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
503 continue_lsp_update_handler(ctrl_state
, pcc_state
, path
, payload
);
507 /* ------------ Internal Functions Called From Controller Thread ------------ */
509 void pcep_thread_finish_event_handler(struct thread
*thread
)
512 struct frr_pthread
*fpt
= THREAD_ARG(thread
);
513 struct ctrl_state
*ctrl_state
= fpt
->data
;
515 assert(ctrl_state
!= NULL
);
517 for (i
= 0; i
< MAX_PCC
; i
++) {
518 if (ctrl_state
->pcc
[i
]) {
519 pcep_pcc_finalize(ctrl_state
, ctrl_state
->pcc
[i
]);
520 ctrl_state
->pcc
[i
] = NULL
;
524 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
525 XFREE(MTYPE_PCEP
, ctrl_state
);
528 atomic_store_explicit(&fpt
->running
, false, memory_order_relaxed
);
531 /* ------------ Controller Thread Timer Handler ------------ */
533 int schedule_thread_timer_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
534 enum pcep_ctrl_timer_type timer_type
,
535 enum pcep_ctrl_timeout_type timeout_type
,
536 uint32_t delay
, void *payload
,
537 struct thread
**thread
,
538 pcep_ctrl_thread_callback timer_cb
)
540 assert(thread
!= NULL
);
542 struct pcep_ctrl_timer_data
*data
;
544 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
545 data
->ctrl_state
= ctrl_state
;
546 data
->timer_type
= timer_type
;
547 data
->timeout_type
= timeout_type
;
548 data
->pcc_id
= pcc_id
;
549 data
->payload
= payload
;
551 thread_add_timer(ctrl_state
->self
, timer_cb
, (void *)data
, delay
,
557 int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
558 enum pcep_ctrl_timer_type timer_type
,
559 enum pcep_ctrl_timeout_type timeout_type
,
560 uint32_t delay
, void *payload
, struct thread
**thread
)
562 return schedule_thread_timer_with_cb(ctrl_state
, pcc_id
, timer_type
,
563 timeout_type
, delay
, payload
,
564 thread
, pcep_thread_timer_handler
);
567 void pcep_thread_timer_handler(struct thread
*thread
)
570 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(thread
);
571 assert(data
!= NULL
);
572 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
573 assert(ctrl_state
!= NULL
);
574 enum pcep_ctrl_timer_type timer_type
= data
->timer_type
;
575 enum pcep_ctrl_timeout_type timeout_type
= data
->timeout_type
;
576 int pcc_id
= data
->pcc_id
;
577 void *param
= data
->payload
;
578 XFREE(MTYPE_PCEP
, data
);
580 struct pcc_state
*pcc_state
= NULL
;
582 switch (timer_type
) {
583 case TM_RECONNECT_PCC
:
584 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
587 pcep_pcc_reconnect(ctrl_state
, pcc_state
);
590 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
593 pcep_pcc_timeout_handler(ctrl_state
, pcc_state
, timeout_type
,
596 case TM_CALCULATE_BEST_PCE
:
597 /* Previous best disconnect so new best should be synced */
598 pcep_pcc_timer_update_best_pce(ctrl_state
, pcc_id
);
600 case TM_SESSION_TIMEOUT_PCC
:
601 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
602 pcep_thread_remove_candidate_path_segments(ctrl_state
,
605 case TM_PCEPLIB_TIMER
:
608 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
609 "Unknown controller timer triggered: %u", timer_type
);
614 void pcep_thread_pcep_event(struct thread
*thread
)
616 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
617 assert(data
!= NULL
);
618 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
619 pcep_event
*event
= data
->payload
;
620 XFREE(MTYPE_PCEP
, data
);
623 for (i
= 0; i
< MAX_PCC
; i
++) {
624 if (ctrl_state
->pcc
[i
]) {
625 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
626 if (pcc_state
->sess
!= event
->session
)
628 pcep_pcc_pcep_event_handler(ctrl_state
, pcc_state
,
633 destroy_pcep_event(event
);
636 /* ------------ Controller Thread Socket Functions ------------ */
638 int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
639 enum pcep_ctrl_socket_type type
, bool is_read
,
640 void *payload
, int fd
, struct thread
**thread
,
641 pcep_ctrl_thread_callback socket_cb
)
643 assert(thread
!= NULL
);
645 struct pcep_ctrl_socket_data
*data
;
647 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
648 data
->ctrl_state
= ctrl_state
;
650 data
->is_read
= is_read
;
652 data
->pcc_id
= pcc_id
;
653 data
->payload
= payload
;
656 thread_add_read(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
659 thread_add_write(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
666 int pcep_thread_socket_write(void *fpt
, void **thread
, int fd
, void *payload
,
667 pcep_ctrl_thread_callback socket_cb
)
669 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
671 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, false,
672 payload
, fd
, (struct thread
**)thread
,
676 int pcep_thread_socket_read(void *fpt
, void **thread
, int fd
, void *payload
,
677 pcep_ctrl_thread_callback socket_cb
)
679 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
681 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, true,
682 payload
, fd
, (struct thread
**)thread
,
686 int pcep_thread_send_ctrl_event(void *fpt
, void *payload
,
687 pcep_ctrl_thread_callback cb
)
689 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
691 return send_to_thread_with_cb(ctrl_state
, 0, EV_PCEPLIB_EVENT
, 0,
695 /* ------------ Controller Thread Event Handler ------------ */
697 int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
698 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
701 return send_to_thread_with_cb(ctrl_state
, pcc_id
, type
, sub_type
,
702 payload
, pcep_thread_event_handler
);
705 int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
706 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
707 void *payload
, pcep_ctrl_thread_callback event_cb
)
709 struct pcep_ctrl_event_data
*data
;
711 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
712 data
->ctrl_state
= ctrl_state
;
714 data
->sub_type
= sub_type
;
715 data
->pcc_id
= pcc_id
;
716 data
->payload
= payload
;
718 thread_add_event(ctrl_state
->self
, event_cb
, (void *)data
, 0, NULL
);
723 void pcep_thread_event_handler(struct thread
*thread
)
726 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
727 assert(data
!= NULL
);
728 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
729 assert(ctrl_state
!= NULL
);
730 enum pcep_ctrl_event_type type
= data
->type
;
731 uint32_t sub_type
= data
->sub_type
;
732 int pcc_id
= data
->pcc_id
;
733 void *payload
= data
->payload
;
734 XFREE(MTYPE_PCEP
, data
);
736 /* Possible sub-type values */
737 enum pcep_pathd_event_type path_event_type
= PCEP_PATH_UNDEFINED
;
739 /* Possible payload values, maybe an union would be better... */
740 struct path
*path
= NULL
;
741 struct pcc_opts
*pcc_opts
= NULL
;
742 struct pce_opts
*pce_opts
= NULL
;
743 struct pcc_state
*pcc_state
= NULL
;
744 struct pcep_refine_path_event_data
*refine_data
= NULL
;
746 struct path
*path_copy
= NULL
;
747 struct pcep_error
*error
= NULL
;
750 case EV_UPDATE_PCC_OPTS
:
751 assert(payload
!= NULL
);
752 pcc_opts
= (struct pcc_opts
*)payload
;
753 pcep_thread_event_update_pcc_options(ctrl_state
, pcc_opts
);
755 case EV_UPDATE_PCE_OPTS
:
756 assert(payload
!= NULL
);
757 pce_opts
= (struct pce_opts
*)payload
;
758 pcep_thread_event_update_pce_options(ctrl_state
, pcc_id
,
762 pce_opts
= (struct pce_opts
*)payload
;
763 if (pcep_thread_event_remove_pcc(ctrl_state
, pce_opts
) == 0)
764 pcep_pcc_multi_pce_remove_pcc(ctrl_state
,
768 assert(payload
!= NULL
);
769 path_event_type
= (enum pcep_pathd_event_type
)sub_type
;
770 path
= (struct path
*)payload
;
771 pcep_thread_event_pathd_event(ctrl_state
, path_event_type
,
775 assert(payload
!= NULL
);
776 path
= (struct path
*)payload
;
777 pcep_pcc_multi_pce_sync_path(ctrl_state
, pcc_id
,
779 pcep_thread_event_sync_path(ctrl_state
, pcc_id
, path
);
782 pcep_thread_event_sync_done(ctrl_state
, pcc_id
);
784 case EV_RESET_PCC_SESSION
:
785 pcc_state
= pcep_pcc_get_pcc_by_name(ctrl_state
->pcc
,
786 (const char *)payload
);
788 pcep_pcc_disable(ctrl_state
, pcc_state
);
789 pcep_pcc_enable(ctrl_state
, pcc_state
);
791 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
792 "Cannot reset state for PCE: %s",
793 (const char *)payload
);
797 assert(payload
!= NULL
);
798 path
= (struct path
*)payload
;
800 for (int i
= 0; i
< MAX_PCC
; i
++) {
801 if (ctrl_state
->pcc
[i
]) {
802 path_copy
= pcep_copy_path(path
);
803 pcep_pcc_send_report(
804 ctrl_state
, ctrl_state
->pcc
[i
],
805 path_copy
, (bool)sub_type
);
810 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
811 pcep_pcc_send_report(ctrl_state
, pcc_state
, path
,
815 case EV_PATH_REFINED
:
816 assert(payload
!= NULL
);
817 refine_data
= (struct pcep_refine_path_event_data
*)payload
;
818 pcep_thread_path_refined_event(ctrl_state
, refine_data
);
821 assert(payload
!= NULL
);
822 error
= (struct pcep_error
*)payload
;
823 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
824 pcep_pcc_send_error(ctrl_state
, pcc_state
, error
,
827 case EV_PCEPLIB_EVENT
:
828 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
829 "Unexpected event received in controller thread: %u",
835 int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
836 struct pcc_opts
*opts
)
838 assert(opts
!= NULL
);
839 if (ctrl_state
->pcc_opts
!= NULL
) {
840 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
842 ctrl_state
->pcc_opts
= opts
;
846 int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
847 int pcc_id
, struct pce_opts
*pce_opts
)
849 if (!pce_opts
|| !ctrl_state
) {
852 struct pcc_state
*pcc_state
;
853 struct pcc_opts
*pcc_opts
;
856 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
, pce_opts
);
857 if (current_pcc_id
) {
859 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, current_pcc_id
);
861 pcc_state
= pcep_pcc_initialize(ctrl_state
,
862 get_next_id(ctrl_state
));
863 if (set_pcc_state(ctrl_state
, pcc_state
)) {
864 XFREE(MTYPE_PCEP
, pcc_state
);
869 /* Copy the pcc options to delegate it to the update function */
870 pcc_opts
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_opts
));
871 memcpy(pcc_opts
, ctrl_state
->pcc_opts
, sizeof(*pcc_opts
));
873 if (pcep_pcc_update(ctrl_state
, pcc_state
, pcc_opts
, pce_opts
)) {
874 flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE
,
875 "failed to update PCC configuration");
882 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
886 struct pcc_state
*pcc_state
=
887 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
889 remove_pcc_state(ctrl_state
, pcc_state
);
890 pcep_pcc_finalize(ctrl_state
, pcc_state
);
896 int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
)
898 assert(ctrl_state
!= NULL
);
900 for (int i
= 0; i
< MAX_PCC
; i
++) {
901 pcep_thread_event_remove_pcc_by_id(
903 pcep_pcc_get_pcc_id_by_idx(ctrl_state
->pcc
, i
));
908 int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
909 struct pce_opts
*pce_opts
)
911 assert(ctrl_state
!= NULL
);
914 int pcc_id
= pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
,
917 pcep_thread_event_remove_pcc_by_id(ctrl_state
, pcc_id
);
921 XFREE(MTYPE_PCEP
, pce_opts
);
923 pcep_thread_event_remove_pcc_all(ctrl_state
);
929 int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
932 struct pcc_state
*pcc_state
=
933 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
934 pcep_pcc_sync_path(ctrl_state
, pcc_state
, path
);
935 pcep_free_path(path
);
939 int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
, int pcc_id
)
941 struct pcc_state
*pcc_state
=
942 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
943 pcep_pcc_sync_done(ctrl_state
, pcc_state
);
947 int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
948 enum pcep_pathd_event_type type
,
953 for (i
= 0; i
< MAX_PCC
; i
++) {
954 if (ctrl_state
->pcc
[i
]) {
955 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
956 pcep_pcc_pathd_event_handler(ctrl_state
, pcc_state
,
961 pcep_free_path(path
);
967 /* ------------ Main Thread Event Handler ------------ */
969 int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
970 enum pcep_main_event_type type
, void *payload
)
972 struct pcep_main_event_data
*data
;
974 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
975 data
->handler
= ctrl_state
->main_event_handler
;
977 data
->pcc_id
= pcc_id
;
978 data
->payload
= payload
;
980 thread_add_event(ctrl_state
->main
, pcep_main_event_handler
,
981 (void *)data
, 0, NULL
);
985 void pcep_main_event_handler(struct thread
*thread
)
988 struct pcep_main_event_data
*data
= THREAD_ARG(thread
);
989 assert(data
!= NULL
);
990 pcep_main_event_handler_t handler
= data
->handler
;
991 enum pcep_main_event_type type
= data
->type
;
992 int pcc_id
= data
->pcc_id
;
993 void *payload
= data
->payload
;
994 XFREE(MTYPE_PCEP
, data
);
996 handler(type
, pcc_id
, payload
);
1000 /* ------------ Helper functions ------------ */
1002 void set_ctrl_state(struct frr_pthread
*fpt
, struct ctrl_state
*ctrl_state
)
1004 assert(fpt
!= NULL
);
1005 fpt
->data
= ctrl_state
;
1008 struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
)
1010 assert(fpt
!= NULL
);
1011 assert(fpt
->data
!= NULL
);
1013 struct ctrl_state
*ctrl_state
;
1014 ctrl_state
= (struct ctrl_state
*)fpt
->data
;
1015 assert(ctrl_state
!= NULL
);
1019 int get_next_id(struct ctrl_state
*ctrl_state
)
1021 return ++ctrl_state
->pcc_last_id
;
1024 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
)
1026 assert(ctrl_state
!= NULL
);
1027 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1029 int current_pcc_idx
= pcep_pcc_get_free_pcc_idx(ctrl_state
->pcc
);
1030 if (current_pcc_idx
>= 0) {
1031 ctrl_state
->pcc
[current_pcc_idx
] = pcc_state
;
1032 ctrl_state
->pcc_count
++;
1033 PCEP_DEBUG("added pce pcc_id (%d) idx (%d)",
1034 pcep_pcc_get_pcc_id(pcc_state
), current_pcc_idx
);
1037 PCEP_DEBUG("Max number of pce ");
1042 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
1043 struct pcc_state
*pcc_state
)
1045 assert(ctrl_state
!= NULL
);
1046 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1049 idx
= pcep_pcc_get_pcc_idx_by_id(ctrl_state
->pcc
,
1050 pcep_pcc_get_pcc_id(pcc_state
));
1052 ctrl_state
->pcc
[idx
] = NULL
;
1053 ctrl_state
->pcc_count
--;
1054 PCEP_DEBUG("removed pce pcc_id (%d)",
1055 pcep_pcc_get_pcc_id(pcc_state
));
1059 uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t retry_count
)
1061 uint32_t a
= MIN(max
, base
* (1 << retry_count
));
1062 uint64_t r
= frr_weak_random(), m
= RAND_MAX
;
1063 uint32_t b
= (a
/ 2) + (r
* (a
/ 2)) / m
;
1067 const char *timer_type_name(enum pcep_ctrl_timer_type type
)
1072 case TM_RECONNECT_PCC
:
1073 return "RECONNECT_PCC";
1074 case TM_PCEPLIB_TIMER
:
1075 return "PCEPLIB_TIMER";
1078 case TM_CALCULATE_BEST_PCE
:
1080 case TM_SESSION_TIMEOUT_PCC
:
1081 return "TIMEOUT_PCC";
1086 assert(!"Reached end of function where we did not expect to");
1089 const char *timeout_type_name(enum pcep_ctrl_timeout_type type
)
1094 case TO_COMPUTATION_REQUEST
:
1095 return "COMPUTATION_REQUEST";
1100 assert(!"Reached end of function where we did not expect to");