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,
63 struct pcep_ctrl_event_data
{
64 struct ctrl_state
*ctrl_state
;
65 enum pcep_ctrl_event_type type
;
71 struct pcep_main_event_data
{
72 pcep_main_event_handler_t handler
;
74 enum pcep_main_event_type type
;
78 struct pcep_refine_path_event_data
{
79 struct ctrl_state
*ctrl_state
;
81 pcep_refine_callback_t continue_lsp_update_handler
;
86 /* Synchronous call arguments */
88 struct get_counters_args
{
89 struct ctrl_state
*ctrl_state
;
91 struct counters_group
*counters
;
94 struct get_pcep_session_args
{
95 struct ctrl_state
*ctrl_state
;
97 pcep_session
*pcep_session
;
100 /* Internal Functions Called From Main Thread */
101 static int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
);
102 static int pcep_refine_path_event_cb(struct thread
*thread
);
104 /* Internal Functions Called From Controller Thread */
105 static int pcep_thread_finish_event_handler(struct thread
*thread
);
107 /* Controller Thread Timer Handler */
108 static int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
109 enum pcep_ctrl_timer_type timer_type
,
110 enum pcep_ctrl_timeout_type timeout_type
,
111 uint32_t delay
, void *payload
,
112 struct thread
**thread
);
113 static int schedule_thread_timer_with_cb(
114 struct ctrl_state
*ctrl_state
, int pcc_id
,
115 enum pcep_ctrl_timer_type timer_type
,
116 enum pcep_ctrl_timeout_type timeout_type
, uint32_t delay
, void *payload
,
117 struct thread
**thread
, pcep_ctrl_thread_callback timer_cb
);
118 static int pcep_thread_timer_handler(struct thread
*thread
);
120 /* Controller Thread Socket read/write Handler */
121 static int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
122 enum pcep_ctrl_socket_type type
, bool is_read
,
123 void *payload
, int fd
, struct thread
**thread
,
124 pcep_ctrl_thread_callback cb
);
126 /* Controller Thread Event Handler */
127 static int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
128 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
130 static int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
131 enum pcep_ctrl_event_type type
,
132 uint32_t sub_type
, void *payload
,
133 pcep_ctrl_thread_callback event_cb
);
134 static int pcep_thread_event_handler(struct thread
*thread
);
135 static int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
136 struct pcc_opts
*opts
);
137 static int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
139 struct pce_opts
*opts
);
140 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
142 static int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
);
143 static int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
144 struct pce_opts
*pce_opts
);
145 static int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
,
146 int pcc_id
, struct path
*path
);
147 static int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
,
149 static int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
150 enum pcep_pathd_event_type type
,
153 pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
154 struct pcep_refine_path_event_data
*data
);
156 /* Main Thread Event Handler */
157 static int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
158 enum pcep_main_event_type type
, void *payload
);
159 static int pcep_main_event_handler(struct thread
*thread
);
161 /* Helper functions */
162 static void set_ctrl_state(struct frr_pthread
*fpt
,
163 struct ctrl_state
*ctrl_state
);
164 static struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
);
165 int get_next_id(struct ctrl_state
*ctrl_state
);
166 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
);
167 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
168 struct pcc_state
*pcc_state
);
169 static uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t attempt
);
170 static const char *timer_type_name(enum pcep_ctrl_timer_type type
);
171 static const char *timeout_type_name(enum pcep_ctrl_timeout_type type
);
174 /* ------------ API Functions Called from Main Thread ------------ */
176 int pcep_ctrl_initialize(struct thread_master
*main_thread
,
177 struct frr_pthread
**fpt
,
178 pcep_main_event_handler_t event_handler
)
183 struct ctrl_state
*ctrl_state
;
184 struct frr_pthread_attr attr
= {
185 .start
= frr_pthread_attr_default
.start
,
186 .stop
= pcep_ctrl_halt_cb
,
189 PCEP_DEBUG("Initializing pcep module controller");
191 /* Create and start the FRR pthread */
192 *fpt
= frr_pthread_new(&attr
, "PCEP thread", "pcep_controller");
194 flog_err(EC_PATH_SYSTEM_CALL
,
195 "failed to initialize PCEP thread");
198 ret
= frr_pthread_run(*fpt
, NULL
);
200 flog_err(EC_PATH_SYSTEM_CALL
, "failed to create PCEP thread");
203 frr_pthread_wait_running(*fpt
);
205 /* Initialize the thread state */
206 ctrl_state
= XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
));
207 ctrl_state
->main
= main_thread
;
208 ctrl_state
->self
= (*fpt
)->master
;
209 ctrl_state
->main_event_handler
= event_handler
;
210 ctrl_state
->pcc_count
= 0;
211 ctrl_state
->pcc_last_id
= 0;
212 ctrl_state
->pcc_opts
=
213 XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
->pcc_opts
));
214 /* Default to no PCC address defined */
215 ctrl_state
->pcc_opts
->addr
.ipa_type
= IPADDR_NONE
;
216 ctrl_state
->pcc_opts
->port
= PCEP_DEFAULT_PORT
;
218 /* Keep the state reference for events */
219 set_ctrl_state(*fpt
, ctrl_state
);
224 int pcep_ctrl_finalize(struct frr_pthread
**fpt
)
230 PCEP_DEBUG("Finalizing pcep module controller");
233 frr_pthread_stop(*fpt
, NULL
);
240 int pcep_ctrl_update_pcc_options(struct frr_pthread
*fpt
, struct pcc_opts
*opts
)
242 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
243 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCC_OPTS
, 0, opts
);
246 int pcep_ctrl_update_pce_options(struct frr_pthread
*fpt
, struct pce_opts
*opts
)
248 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
249 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCE_OPTS
, 0, opts
);
252 int pcep_ctrl_remove_pcc(struct frr_pthread
*fpt
, struct pce_opts
*pce_opts
)
254 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
255 return send_to_thread(ctrl_state
, 0, EV_REMOVE_PCC
, 0, pce_opts
);
258 int pcep_ctrl_reset_pcc_session(struct frr_pthread
*fpt
, char *pce_name
)
260 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
261 return send_to_thread(ctrl_state
, 0, EV_RESET_PCC_SESSION
, 0, pce_name
);
264 int pcep_ctrl_pathd_event(struct frr_pthread
*fpt
,
265 enum pcep_pathd_event_type type
, struct path
*path
)
267 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
268 return send_to_thread(ctrl_state
, 0, EV_PATHD_EVENT
, type
, path
);
271 int pcep_ctrl_sync_path(struct frr_pthread
*fpt
, int pcc_id
, struct path
*path
)
273 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
274 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_PATH
, 0, path
);
277 int pcep_ctrl_sync_done(struct frr_pthread
*fpt
, int pcc_id
)
279 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
280 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_DONE
, 0, NULL
);
283 struct counters_group
*pcep_ctrl_get_counters(struct frr_pthread
*fpt
,
286 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
287 struct counters_group
*counters
= NULL
;
288 struct pcc_state
*pcc_state
;
289 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
291 counters
= pcep_lib_copy_counters(pcc_state
->sess
);
296 pcep_session
*pcep_ctrl_get_pcep_session(struct frr_pthread
*fpt
, int pcc_id
)
298 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
299 struct pcc_state
*pcc_state
;
300 pcep_session
*session
= NULL
;
302 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
304 session
= pcep_lib_copy_pcep_session(pcc_state
->sess
);
309 struct pcep_pcc_info
*pcep_ctrl_get_pcc_info(struct frr_pthread
*fpt
,
310 const char *pce_name
)
312 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
313 struct pcep_pcc_info
*pcc_info
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_info
));
314 if( pcc_info
&& ctrl_state
){
315 strlcpy(pcc_info
->pce_name
, pce_name
, sizeof(pcc_info
->pce_name
));
316 pcep_pcc_copy_pcc_info(ctrl_state
->pcc
, pcc_info
);
322 int pcep_ctrl_send_report(struct frr_pthread
*fpt
, int pcc_id
,
323 struct path
*path
, bool is_stable
)
325 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
326 return send_to_thread(ctrl_state
, pcc_id
, EV_SEND_REPORT
, is_stable
,
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 int 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 return 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_remove_candidate_path_segments(struct ctrl_state
*ctrl_state
,
372 struct pcc_state
*pcc_state
)
376 /* Will be deleted when the event is handled */
377 char *originator
= XSTRDUP(MTYPE_PCEP
, pcc_state
->originator
);
378 PCEP_DEBUG("schedule candidate path segments removal for originator %s",
380 send_to_main(ctrl_state
, pcep_pcc_get_pcc_id(pcc_state
),
381 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
, originator
);
384 void pcep_thread_schedule_sync_best_pce(struct ctrl_state
*ctrl_state
,
385 int pcc_id
, int delay
,
386 struct thread
**thread
)
389 schedule_thread_timer(ctrl_state
, pcc_id
, TM_CALCULATE_BEST_PCE
,
390 TO_UNDEFINED
, delay
, NULL
, thread
);
393 void pcep_thread_cancel_timer(struct thread
**thread
)
395 if (thread
== NULL
|| *thread
== NULL
) {
399 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(*thread
);
400 PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data
->timer_type
),
401 timeout_type_name(data
->timeout_type
));
403 XFREE(MTYPE_PCEP
, data
);
406 if ((*thread
)->master
->owner
== pthread_self()) {
407 thread_cancel(thread
);
409 thread_cancel_async((*thread
)->master
, thread
, NULL
);
413 void pcep_thread_schedule_reconnect(struct ctrl_state
*ctrl_state
, int pcc_id
,
414 int retry_count
, struct thread
**thread
)
416 uint32_t delay
= backoff_delay(MAX_RECONNECT_DELAY
, 1, retry_count
);
417 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay
,
419 schedule_thread_timer(ctrl_state
, pcc_id
, TM_RECONNECT_PCC
,
420 TO_UNDEFINED
, delay
, NULL
, thread
);
423 void pcep_thread_schedule_timeout(struct ctrl_state
*ctrl_state
, int pcc_id
,
424 enum pcep_ctrl_timeout_type timeout_type
,
425 uint32_t delay
, void *param
,
426 struct thread
**thread
)
428 assert(timeout_type
> TO_UNDEFINED
);
429 assert(timeout_type
< TO_MAX
);
430 PCEP_DEBUG("Schedule timeout %s for %us",
431 timeout_type_name(timeout_type
), delay
);
432 schedule_thread_timer(ctrl_state
, pcc_id
, TM_TIMEOUT
, timeout_type
,
433 delay
, param
, thread
);
436 void pcep_thread_schedule_pceplib_timer(struct ctrl_state
*ctrl_state
,
437 int delay
, void *payload
,
438 struct thread
**thread
,
439 pcep_ctrl_thread_callback timer_cb
)
441 PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay
);
442 schedule_thread_timer_with_cb(ctrl_state
, 0, TM_PCEPLIB_TIMER
,
443 TO_UNDEFINED
, delay
, payload
, thread
,
447 void pcep_thread_schedule_session_timeout(struct ctrl_state
*ctrl_state
,
448 int pcc_id
, int delay
,
449 struct thread
**thread
)
451 PCEP_DEBUG("Schedule session_timeout interval for %us", delay
);
452 schedule_thread_timer(ctrl_state
, pcc_id
, TM_SESSION_TIMEOUT_PCC
,
453 TO_UNDEFINED
, delay
, NULL
, thread
);
456 int pcep_thread_pcc_count(struct ctrl_state
*ctrl_state
)
458 if (ctrl_state
== NULL
) {
462 return ctrl_state
->pcc_count
;
465 int pcep_thread_refine_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
466 pcep_refine_callback_t cb
, struct path
*path
,
469 struct pcep_refine_path_event_data
*data
;
471 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
472 data
->ctrl_state
= ctrl_state
;
474 data
->pcc_id
= pcc_id
;
475 data
->continue_lsp_update_handler
= cb
;
476 data
->payload
= payload
;
478 thread_add_event(ctrl_state
->main
, pcep_refine_path_event_cb
,
479 (void *)data
, 0, NULL
);
483 void pcep_thread_path_refined_event(struct ctrl_state
*ctrl_state
,
484 struct pcep_refine_path_event_data
*data
)
486 assert(data
!= NULL
);
487 int pcc_id
= data
->pcc_id
;
488 pcep_refine_callback_t continue_lsp_update_handler
= data
->continue_lsp_update_handler
;
489 assert(continue_lsp_update_handler
!= NULL
);
490 struct path
*path
= data
->path
;
491 void *payload
= data
->payload
;
492 struct pcc_state
*pcc_state
= NULL
;
493 XFREE(MTYPE_PCEP
, data
);
495 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
496 continue_lsp_update_handler(ctrl_state
, pcc_state
, path
, payload
);
500 /* ------------ Internal Functions Called From Controller Thread ------------ */
502 int pcep_thread_finish_event_handler(struct thread
*thread
)
505 struct frr_pthread
*fpt
= THREAD_ARG(thread
);
506 struct ctrl_state
*ctrl_state
= fpt
->data
;
508 assert(ctrl_state
!= NULL
);
510 for (i
= 0; i
< MAX_PCC
; i
++) {
511 if (ctrl_state
->pcc
[i
]) {
512 pcep_pcc_finalize(ctrl_state
, ctrl_state
->pcc
[i
]);
513 ctrl_state
->pcc
[i
] = NULL
;
517 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
518 XFREE(MTYPE_PCEP
, ctrl_state
);
521 atomic_store_explicit(&fpt
->running
, false, memory_order_relaxed
);
525 /* ------------ Controller Thread Timer Handler ------------ */
527 int schedule_thread_timer_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
528 enum pcep_ctrl_timer_type timer_type
,
529 enum pcep_ctrl_timeout_type timeout_type
,
530 uint32_t delay
, void *payload
,
531 struct thread
**thread
,
532 pcep_ctrl_thread_callback timer_cb
)
534 assert(thread
!= NULL
);
536 struct pcep_ctrl_timer_data
*data
;
538 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
539 data
->ctrl_state
= ctrl_state
;
540 data
->timer_type
= timer_type
;
541 data
->timeout_type
= timeout_type
;
542 data
->pcc_id
= pcc_id
;
543 data
->payload
= payload
;
545 thread_add_timer(ctrl_state
->self
, timer_cb
, (void *)data
, delay
,
551 int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
552 enum pcep_ctrl_timer_type timer_type
,
553 enum pcep_ctrl_timeout_type timeout_type
,
554 uint32_t delay
, void *payload
, struct thread
**thread
)
556 return schedule_thread_timer_with_cb(ctrl_state
, pcc_id
, timer_type
,
557 timeout_type
, delay
, payload
,
558 thread
, pcep_thread_timer_handler
);
561 int pcep_thread_timer_handler(struct thread
*thread
)
564 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(thread
);
565 assert(data
!= NULL
);
566 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
567 assert(ctrl_state
!= NULL
);
568 enum pcep_ctrl_timer_type timer_type
= data
->timer_type
;
569 enum pcep_ctrl_timeout_type timeout_type
= data
->timeout_type
;
570 int pcc_id
= data
->pcc_id
;
571 void *param
= data
->payload
;
572 XFREE(MTYPE_PCEP
, data
);
575 struct pcc_state
*pcc_state
= NULL
;
577 switch (timer_type
) {
578 case TM_RECONNECT_PCC
:
579 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
582 pcep_pcc_reconnect(ctrl_state
, pcc_state
);
585 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
588 pcep_pcc_timeout_handler(ctrl_state
, pcc_state
, timeout_type
,
591 case TM_CALCULATE_BEST_PCE
:
592 /* Previous best disconnect so new best should be synced */
593 ret
= pcep_pcc_timer_update_best_pce(ctrl_state
, pcc_id
);
595 case TM_SESSION_TIMEOUT_PCC
:
596 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
597 pcep_thread_remove_candidate_path_segments(ctrl_state
,
601 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
602 "Unknown controller timer triggered: %u", timer_type
);
609 int pcep_thread_pcep_event(struct thread
*thread
)
611 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
612 assert(data
!= NULL
);
613 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
614 pcep_event
*event
= data
->payload
;
615 XFREE(MTYPE_PCEP
, data
);
618 for (i
= 0; i
< MAX_PCC
; i
++) {
619 if (ctrl_state
->pcc
[i
]) {
620 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
621 if (pcc_state
->sess
!= event
->session
)
623 pcep_pcc_pcep_event_handler(ctrl_state
, pcc_state
,
628 destroy_pcep_event(event
);
633 /* ------------ Controller Thread Socket Functions ------------ */
635 int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
636 enum pcep_ctrl_socket_type type
, bool is_read
,
637 void *payload
, int fd
, struct thread
**thread
,
638 pcep_ctrl_thread_callback socket_cb
)
640 assert(thread
!= NULL
);
642 struct pcep_ctrl_socket_data
*data
;
644 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
645 data
->ctrl_state
= ctrl_state
;
647 data
->is_read
= is_read
;
649 data
->pcc_id
= pcc_id
;
650 data
->payload
= payload
;
653 thread_add_read(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
656 thread_add_write(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
663 int pcep_thread_socket_write(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
, false,
669 payload
, fd
, (struct thread
**)thread
,
673 int pcep_thread_socket_read(void *fpt
, void **thread
, int fd
, void *payload
,
674 pcep_ctrl_thread_callback socket_cb
)
676 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
678 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, true,
679 payload
, fd
, (struct thread
**)thread
,
683 int pcep_thread_send_ctrl_event(void *fpt
, void *payload
,
684 pcep_ctrl_thread_callback cb
)
686 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
688 return send_to_thread_with_cb(ctrl_state
, 0, EV_PCEPLIB_EVENT
, 0,
692 /* ------------ Controller Thread Event Handler ------------ */
694 int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
695 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
698 return send_to_thread_with_cb(ctrl_state
, pcc_id
, type
, sub_type
,
699 payload
, pcep_thread_event_handler
);
702 int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
703 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
704 void *payload
, pcep_ctrl_thread_callback event_cb
)
706 struct pcep_ctrl_event_data
*data
;
708 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
709 data
->ctrl_state
= ctrl_state
;
711 data
->sub_type
= sub_type
;
712 data
->pcc_id
= pcc_id
;
713 data
->payload
= payload
;
715 thread_add_event(ctrl_state
->self
, event_cb
, (void *)data
, 0, NULL
);
720 int pcep_thread_event_handler(struct thread
*thread
)
723 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
724 assert(data
!= NULL
);
725 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
726 assert(ctrl_state
!= NULL
);
727 enum pcep_ctrl_event_type type
= data
->type
;
728 uint32_t sub_type
= data
->sub_type
;
729 int pcc_id
= data
->pcc_id
;
730 void *payload
= data
->payload
;
731 XFREE(MTYPE_PCEP
, data
);
735 /* Possible sub-type values */
736 enum pcep_pathd_event_type path_event_type
= PCEP_PATH_UNDEFINED
;
738 /* Possible payload values, maybe an union would be better... */
739 struct path
*path
= NULL
;
740 struct pcc_opts
*pcc_opts
= NULL
;
741 struct pce_opts
*pce_opts
= NULL
;
742 struct pcc_state
*pcc_state
= NULL
;
743 struct pcep_refine_path_event_data
*refine_data
= NULL
;
745 struct path
*path_copy
= NULL
;
748 case EV_UPDATE_PCC_OPTS
:
749 assert(payload
!= NULL
);
750 pcc_opts
= (struct pcc_opts
*)payload
;
751 ret
= pcep_thread_event_update_pcc_options(ctrl_state
,
754 case EV_UPDATE_PCE_OPTS
:
755 assert(payload
!= NULL
);
756 pce_opts
= (struct pce_opts
*)payload
;
757 ret
= pcep_thread_event_update_pce_options(ctrl_state
, pcc_id
,
761 pce_opts
= (struct pce_opts
*)payload
;
762 ret
= pcep_thread_event_remove_pcc(ctrl_state
, pce_opts
);
764 ret
= pcep_pcc_multi_pce_remove_pcc(ctrl_state
,
769 assert(payload
!= NULL
);
770 path_event_type
= (enum pcep_pathd_event_type
)sub_type
;
771 path
= (struct path
*)payload
;
772 ret
= pcep_thread_event_pathd_event(ctrl_state
, path_event_type
,
776 assert(payload
!= NULL
);
777 path
= (struct path
*)payload
;
778 pcep_pcc_multi_pce_sync_path(ctrl_state
, pcc_id
,
780 pcep_thread_event_sync_path(ctrl_state
, pcc_id
, path
);
783 ret
= pcep_thread_event_sync_done(ctrl_state
, pcc_id
);
785 case EV_RESET_PCC_SESSION
:
786 pcc_state
= pcep_pcc_get_pcc_by_name(ctrl_state
->pcc
,
787 (const char *)payload
);
789 pcep_pcc_disable(ctrl_state
, pcc_state
);
790 ret
= pcep_pcc_enable(ctrl_state
, pcc_state
);
792 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
793 "Cannot reset state for PCE: %s",
794 (const char *)payload
);
798 assert(payload
!= NULL
);
799 path
= (struct path
*)payload
;
801 for (int i
= 0; i
< MAX_PCC
; i
++) {
802 if (ctrl_state
->pcc
[i
]) {
803 path_copy
= pcep_copy_path(path
);
804 pcep_pcc_send_report(
805 ctrl_state
, ctrl_state
->pcc
[i
],
806 path_copy
, (bool)sub_type
);
811 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
812 pcep_pcc_send_report(ctrl_state
, pcc_state
, path
,
816 case EV_PATH_REFINED
:
817 assert(payload
!= NULL
);
818 refine_data
= (struct pcep_refine_path_event_data
*)payload
;
819 pcep_thread_path_refined_event(ctrl_state
, refine_data
);
822 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
823 "Unexpected event received in controller thread: %u",
831 int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
832 struct pcc_opts
*opts
)
834 assert(opts
!= NULL
);
835 if (ctrl_state
->pcc_opts
!= NULL
) {
836 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
838 ctrl_state
->pcc_opts
= opts
;
842 int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
843 int pcc_id
, struct pce_opts
*pce_opts
)
845 if (!pce_opts
|| !ctrl_state
) {
848 struct pcc_state
*pcc_state
;
849 struct pcc_opts
*pcc_opts
;
852 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
, pce_opts
);
853 if (current_pcc_id
) {
855 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, current_pcc_id
);
857 pcc_state
= pcep_pcc_initialize(ctrl_state
,
858 get_next_id(ctrl_state
));
859 if (set_pcc_state(ctrl_state
, pcc_state
)) {
860 XFREE(MTYPE_PCEP
, pcc_state
);
865 /* Copy the pcc options to delegate it to the update function */
866 pcc_opts
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_opts
));
867 memcpy(pcc_opts
, ctrl_state
->pcc_opts
, sizeof(*pcc_opts
));
869 if (pcep_pcc_update(ctrl_state
, pcc_state
, pcc_opts
, pce_opts
)) {
870 flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE
,
871 "failed to update PCC configuration");
878 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
882 struct pcc_state
*pcc_state
=
883 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
885 remove_pcc_state(ctrl_state
, pcc_state
);
886 pcep_pcc_finalize(ctrl_state
, pcc_state
);
892 int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
)
894 assert(ctrl_state
!= NULL
);
896 for (int i
= 0; i
< MAX_PCC
; i
++) {
897 pcep_thread_event_remove_pcc_by_id(
899 pcep_pcc_get_pcc_id_by_idx(ctrl_state
->pcc
, i
));
904 int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
905 struct pce_opts
*pce_opts
)
907 assert(ctrl_state
!= NULL
);
910 int pcc_id
= pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
,
913 pcep_thread_event_remove_pcc_by_id(ctrl_state
, pcc_id
);
917 XFREE(MTYPE_PCEP
, pce_opts
);
919 pcep_thread_event_remove_pcc_all(ctrl_state
);
925 int pcep_thread_event_sync_path(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_path(ctrl_state
, pcc_state
, path
);
931 pcep_free_path(path
);
935 int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
, int pcc_id
)
937 struct pcc_state
*pcc_state
=
938 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
939 pcep_pcc_sync_done(ctrl_state
, pcc_state
);
943 int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
944 enum pcep_pathd_event_type type
,
949 for (i
= 0; i
< MAX_PCC
; i
++) {
950 if (ctrl_state
->pcc
[i
]) {
951 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
952 pcep_pcc_pathd_event_handler(ctrl_state
, pcc_state
,
957 pcep_free_path(path
);
963 /* ------------ Main Thread Event Handler ------------ */
965 int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
966 enum pcep_main_event_type type
, void *payload
)
968 struct pcep_main_event_data
*data
;
970 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
971 data
->handler
= ctrl_state
->main_event_handler
;
973 data
->pcc_id
= pcc_id
;
974 data
->payload
= payload
;
976 thread_add_event(ctrl_state
->main
, pcep_main_event_handler
,
977 (void *)data
, 0, NULL
);
981 int pcep_main_event_handler(struct thread
*thread
)
984 struct pcep_main_event_data
*data
= THREAD_ARG(thread
);
985 assert(data
!= NULL
);
986 pcep_main_event_handler_t handler
= data
->handler
;
987 enum pcep_main_event_type type
= data
->type
;
988 int pcc_id
= data
->pcc_id
;
989 void *payload
= data
->payload
;
990 XFREE(MTYPE_PCEP
, data
);
992 return handler(type
, pcc_id
, payload
);
996 /* ------------ Helper functions ------------ */
998 void set_ctrl_state(struct frr_pthread
*fpt
, struct ctrl_state
*ctrl_state
)
1000 assert(fpt
!= NULL
);
1001 fpt
->data
= ctrl_state
;
1004 struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
)
1006 assert(fpt
!= NULL
);
1007 assert(fpt
->data
!= NULL
);
1009 struct ctrl_state
*ctrl_state
;
1010 ctrl_state
= (struct ctrl_state
*)fpt
->data
;
1011 assert(ctrl_state
!= NULL
);
1015 int get_next_id(struct ctrl_state
*ctrl_state
)
1017 return ++ctrl_state
->pcc_last_id
;
1020 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
)
1022 assert(ctrl_state
!= NULL
);
1023 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1025 int current_pcc_idx
= pcep_pcc_get_free_pcc_idx(ctrl_state
->pcc
);
1026 if (current_pcc_idx
>= 0) {
1027 ctrl_state
->pcc
[current_pcc_idx
] = pcc_state
;
1028 ctrl_state
->pcc_count
++;
1029 PCEP_DEBUG("added pce pcc_id (%d) idx (%d)",
1030 pcep_pcc_get_pcc_id(pcc_state
), current_pcc_idx
);
1033 PCEP_DEBUG("Max number of pce ");
1038 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
1039 struct pcc_state
*pcc_state
)
1041 assert(ctrl_state
!= NULL
);
1042 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1045 idx
= pcep_pcc_get_pcc_idx_by_id(ctrl_state
->pcc
,
1046 pcep_pcc_get_pcc_id(pcc_state
));
1048 ctrl_state
->pcc
[idx
] = NULL
;
1049 ctrl_state
->pcc_count
--;
1050 PCEP_DEBUG("removed pce pcc_id (%d)",
1051 pcep_pcc_get_pcc_id(pcc_state
));
1055 uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t retry_count
)
1057 uint32_t a
= min(max
, base
* (1 << retry_count
));
1058 uint64_t r
= frr_weak_random(), m
= RAND_MAX
;
1059 uint32_t b
= (a
/ 2) + (r
* (a
/ 2)) / m
;
1063 const char *timer_type_name(enum pcep_ctrl_timer_type type
)
1068 case TM_RECONNECT_PCC
:
1069 return "RECONNECT_PCC";
1070 case TM_PCEPLIB_TIMER
:
1071 return "PCEPLIB_TIMER";
1079 const char *timeout_type_name(enum pcep_ctrl_timeout_type type
)
1084 case TO_COMPUTATION_REQUEST
:
1085 return "COMPUTATION_REQUEST";