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
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,
61 struct pcep_ctrl_event_data
{
62 struct ctrl_state
*ctrl_state
;
63 enum pcep_ctrl_event_type type
;
69 struct pcep_main_event_data
{
70 pcep_main_event_handler_t handler
;
72 enum pcep_main_event_type type
;
76 /* Synchronous call arguments */
78 struct get_counters_args
{
79 struct ctrl_state
*ctrl_state
;
81 struct counters_group
*counters
;
84 struct send_report_args
{
85 struct ctrl_state
*ctrl_state
;
90 struct get_pcep_session_args
{
91 struct ctrl_state
*ctrl_state
;
93 pcep_session
*pcep_session
;
96 /* Internal Functions Called From Main Thread */
97 static int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
);
99 /* Internal Functions Called From Controller Thread */
100 static int pcep_thread_finish_event_handler(struct thread
*thread
);
101 static int pcep_thread_get_counters_callback(struct thread
*t
);
102 static int pcep_thread_send_report_callback(struct thread
*t
);
103 static int pcep_thread_get_pcep_session_callback(struct thread
*t
);
104 static int pcep_thread_get_pcc_info_callback(struct thread
*t
);
106 /* Controller Thread Timer Handler */
107 static int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
108 enum pcep_ctrl_timer_type timer_type
,
109 enum pcep_ctrl_timeout_type timeout_type
,
110 uint32_t delay
, void *payload
,
111 struct thread
**thread
);
112 static int schedule_thread_timer_with_cb(
113 struct ctrl_state
*ctrl_state
, int pcc_id
,
114 enum pcep_ctrl_timer_type timer_type
,
115 enum pcep_ctrl_timeout_type timeout_type
, uint32_t delay
, void *payload
,
116 struct thread
**thread
, pcep_ctrl_thread_callback timer_cb
);
117 static int pcep_thread_timer_handler(struct thread
*thread
);
119 /* Controller Thread Socket read/write Handler */
120 static int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
121 enum pcep_ctrl_socket_type type
, bool is_read
,
122 void *payload
, int fd
, struct thread
**thread
,
123 pcep_ctrl_thread_callback cb
);
125 /* Controller Thread Event Handler */
126 static int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
127 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
129 static int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
130 enum pcep_ctrl_event_type type
,
131 uint32_t sub_type
, void *payload
,
132 pcep_ctrl_thread_callback event_cb
);
133 static int pcep_thread_event_handler(struct thread
*thread
);
134 static int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
135 struct pcc_opts
*opts
);
136 static int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
138 struct pce_opts
*opts
);
139 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
141 static int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
);
142 static int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
143 struct pce_opts
*pce_opts
);
144 static int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
,
145 int pcc_id
, struct path
*path
);
146 static int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
,
148 static int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
149 enum pcep_pathd_event_type type
,
152 /* Main Thread Event Handler */
153 static int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
154 enum pcep_main_event_type type
, void *payload
);
155 static int pcep_main_event_handler(struct thread
*thread
);
157 /* Helper functions */
158 static void set_ctrl_state(struct frr_pthread
*fpt
,
159 struct ctrl_state
*ctrl_state
);
160 static struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
);
161 int get_next_id(struct ctrl_state
*ctrl_state
);
162 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
);
163 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
164 struct pcc_state
*pcc_state
);
165 static uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t attempt
);
166 static const char *timer_type_name(enum pcep_ctrl_timer_type type
);
167 static const char *timeout_type_name(enum pcep_ctrl_timeout_type type
);
170 /* ------------ API Functions Called from Main Thread ------------ */
172 int pcep_ctrl_initialize(struct thread_master
*main_thread
,
173 struct frr_pthread
**fpt
,
174 pcep_main_event_handler_t event_handler
)
179 struct ctrl_state
*ctrl_state
;
180 struct frr_pthread_attr attr
= {
181 .start
= frr_pthread_attr_default
.start
,
182 .stop
= pcep_ctrl_halt_cb
,
185 PCEP_DEBUG("Initializing pcep module controller");
187 /* Create and start the FRR pthread */
188 *fpt
= frr_pthread_new(&attr
, "PCEP thread", "pcep_controller");
190 flog_err(EC_PATH_SYSTEM_CALL
,
191 "failed to initialize PCEP thread");
194 ret
= frr_pthread_run(*fpt
, NULL
);
196 flog_err(EC_PATH_SYSTEM_CALL
, "failed to create PCEP thread");
199 frr_pthread_wait_running(*fpt
);
201 /* Initialize the thread state */
202 ctrl_state
= XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
));
203 ctrl_state
->main
= main_thread
;
204 ctrl_state
->self
= (*fpt
)->master
;
205 ctrl_state
->main_event_handler
= event_handler
;
206 ctrl_state
->pcc_count
= 0;
207 ctrl_state
->pcc_last_id
= 0;
208 ctrl_state
->pcc_opts
=
209 XCALLOC(MTYPE_PCEP
, sizeof(*ctrl_state
->pcc_opts
));
210 /* Default to no PCC address defined */
211 ctrl_state
->pcc_opts
->addr
.ipa_type
= IPADDR_NONE
;
212 ctrl_state
->pcc_opts
->port
= PCEP_DEFAULT_PORT
;
214 /* Keep the state reference for events */
215 set_ctrl_state(*fpt
, ctrl_state
);
220 int pcep_ctrl_finalize(struct frr_pthread
**fpt
)
226 PCEP_DEBUG("Finalizing pcep module controller");
229 frr_pthread_stop(*fpt
, NULL
);
236 int pcep_ctrl_update_pcc_options(struct frr_pthread
*fpt
, struct pcc_opts
*opts
)
238 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
239 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCC_OPTS
, 0, opts
);
242 int pcep_ctrl_update_pce_options(struct frr_pthread
*fpt
, struct pce_opts
*opts
)
244 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
245 return send_to_thread(ctrl_state
, 0, EV_UPDATE_PCE_OPTS
, 0, opts
);
248 int pcep_ctrl_remove_pcc(struct frr_pthread
*fpt
, struct pce_opts
*pce_opts
)
250 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
251 return send_to_thread(ctrl_state
, 0, EV_REMOVE_PCC
, 0, pce_opts
);
254 int pcep_ctrl_reset_pcc_session(struct frr_pthread
*fpt
, char *pce_name
)
256 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
257 return send_to_thread(ctrl_state
, 0, EV_RESET_PCC_SESSION
, 0, pce_name
);
260 int pcep_ctrl_pathd_event(struct frr_pthread
*fpt
,
261 enum pcep_pathd_event_type type
, struct path
*path
)
263 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
264 return send_to_thread(ctrl_state
, 0, EV_PATHD_EVENT
, type
, path
);
267 int pcep_ctrl_sync_path(struct frr_pthread
*fpt
, int pcc_id
, struct path
*path
)
269 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
270 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_PATH
, 0, path
);
273 int pcep_ctrl_sync_done(struct frr_pthread
*fpt
, int pcc_id
)
275 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
276 return send_to_thread(ctrl_state
, pcc_id
, EV_SYNC_DONE
, 0, NULL
);
279 struct counters_group
*pcep_ctrl_get_counters(struct frr_pthread
*fpt
,
282 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
283 struct get_counters_args args
= {
284 .ctrl_state
= ctrl_state
, .pcc_id
= pcc_id
, .counters
= NULL
};
285 thread_execute(ctrl_state
->self
, pcep_thread_get_counters_callback
,
287 return args
.counters
;
290 pcep_session
*pcep_ctrl_get_pcep_session(struct frr_pthread
*fpt
, int pcc_id
)
292 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
293 struct get_pcep_session_args args
= {.ctrl_state
= ctrl_state
,
295 .pcep_session
= NULL
};
296 thread_execute(ctrl_state
->self
, pcep_thread_get_pcep_session_callback
,
298 return args
.pcep_session
;
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
*args
= XCALLOC(MTYPE_PCEP
, sizeof(*args
));
306 args
->ctrl_state
= ctrl_state
;
307 strncpy(args
->pce_name
, pce_name
, sizeof(args
->pce_name
));
308 thread_execute(ctrl_state
->self
, pcep_thread_get_pcc_info_callback
,
314 void pcep_ctrl_send_report(struct frr_pthread
*fpt
, int pcc_id
,
317 /* Sends a report stynchronously */
318 struct ctrl_state
*ctrl_state
= get_ctrl_state(fpt
);
319 struct send_report_args args
= {
320 .ctrl_state
= ctrl_state
, .pcc_id
= pcc_id
, .path
= path
};
321 thread_execute(ctrl_state
->self
, pcep_thread_send_report_callback
,
325 /* ------------ Internal Functions Called from Main Thread ------------ */
327 int pcep_ctrl_halt_cb(struct frr_pthread
*fpt
, void **res
)
329 thread_add_event(fpt
->master
, pcep_thread_finish_event_handler
,
330 (void *)fpt
, 0, NULL
);
331 pthread_join(fpt
->thread
, res
);
337 /* ------------ API Functions Called From Controller Thread ------------ */
339 void pcep_thread_start_sync(struct ctrl_state
*ctrl_state
, int pcc_id
)
341 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_START_SYNC
, NULL
);
344 void pcep_thread_update_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
347 send_to_main(ctrl_state
, pcc_id
, PCEP_MAIN_EVENT_UPDATE_CANDIDATE
,
351 void pcep_thread_remove_candidate_path_segments(struct ctrl_state
*ctrl_state
,
352 struct pcc_state
*pcc_state
)
356 /* Will be deleted when the event is handled */
357 char *originator
= XSTRDUP(MTYPE_PCEP
, pcc_state
->originator
);
358 PCEP_DEBUG("schedule candidate path segments removal for originator %s",
360 send_to_main(ctrl_state
, pcep_pcc_get_pcc_id(pcc_state
),
361 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
, originator
);
364 void pcep_thread_schedule_sync_best_pce(struct ctrl_state
*ctrl_state
,
365 int pcc_id
, int delay
,
366 struct thread
**thread
)
369 schedule_thread_timer(ctrl_state
, pcc_id
, TM_CALCULATE_BEST_PCE
,
370 TO_UNDEFINED
, delay
, NULL
, thread
);
373 void pcep_thread_cancel_timer(struct thread
**thread
)
375 if (thread
== NULL
|| *thread
== NULL
) {
379 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(*thread
);
380 PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data
->timer_type
),
381 timeout_type_name(data
->timeout_type
));
383 XFREE(MTYPE_PCEP
, data
);
386 if ((*thread
)->master
->owner
== pthread_self()) {
387 thread_cancel(thread
);
389 thread_cancel_async((*thread
)->master
, thread
, NULL
);
393 void pcep_thread_schedule_reconnect(struct ctrl_state
*ctrl_state
, int pcc_id
,
394 int retry_count
, struct thread
**thread
)
396 uint32_t delay
= backoff_delay(MAX_RECONNECT_DELAY
, 1, retry_count
);
397 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay
,
399 schedule_thread_timer(ctrl_state
, pcc_id
, TM_RECONNECT_PCC
,
400 TO_UNDEFINED
, delay
, NULL
, thread
);
403 void pcep_thread_schedule_timeout(struct ctrl_state
*ctrl_state
, int pcc_id
,
404 enum pcep_ctrl_timeout_type timeout_type
,
405 uint32_t delay
, void *param
,
406 struct thread
**thread
)
408 assert(timeout_type
> TO_UNDEFINED
);
409 assert(timeout_type
< TO_MAX
);
410 PCEP_DEBUG("Schedule timeout %s for %us",
411 timeout_type_name(timeout_type
), delay
);
412 schedule_thread_timer(ctrl_state
, pcc_id
, TM_TIMEOUT
, timeout_type
,
413 delay
, param
, thread
);
416 void pcep_thread_schedule_pceplib_timer(struct ctrl_state
*ctrl_state
,
417 int delay
, void *payload
,
418 struct thread
**thread
,
419 pcep_ctrl_thread_callback timer_cb
)
421 PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay
);
422 schedule_thread_timer_with_cb(ctrl_state
, 0, TM_PCEPLIB_TIMER
,
423 TO_UNDEFINED
, delay
, payload
, thread
,
427 void pcep_thread_schedule_session_timeout(struct ctrl_state
*ctrl_state
,
428 int pcc_id
, int delay
,
429 struct thread
**thread
)
431 PCEP_DEBUG("Schedule session_timeout interval for %us", delay
);
432 schedule_thread_timer(ctrl_state
, pcc_id
, TM_SESSION_TIMEOUT_PCC
,
433 TO_UNDEFINED
, delay
, NULL
, thread
);
436 int pcep_thread_pcc_count(struct ctrl_state
*ctrl_state
)
438 if (ctrl_state
== NULL
) {
442 return ctrl_state
->pcc_count
;
445 /* ------------ Internal Functions Called From Controller Thread ------------ */
447 int pcep_thread_finish_event_handler(struct thread
*thread
)
450 struct frr_pthread
*fpt
= THREAD_ARG(thread
);
451 struct ctrl_state
*ctrl_state
= fpt
->data
;
453 assert(ctrl_state
!= NULL
);
455 for (i
= 0; i
< MAX_PCC
; i
++) {
456 if (ctrl_state
->pcc
[i
]) {
457 pcep_pcc_finalize(ctrl_state
, ctrl_state
->pcc
[i
]);
458 ctrl_state
->pcc
[i
] = NULL
;
462 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
463 XFREE(MTYPE_PCEP
, ctrl_state
);
466 atomic_store_explicit(&fpt
->running
, false, memory_order_relaxed
);
470 int pcep_thread_get_counters_callback(struct thread
*t
)
472 struct get_counters_args
*args
= THREAD_ARG(t
);
473 assert(args
!= NULL
);
474 struct ctrl_state
*ctrl_state
= args
->ctrl_state
;
475 assert(ctrl_state
!= NULL
);
476 struct pcc_state
*pcc_state
;
478 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, args
->pcc_id
);
480 args
->counters
= pcep_lib_copy_counters(pcc_state
->sess
);
482 args
->counters
= NULL
;
488 int pcep_thread_send_report_callback(struct thread
*t
)
490 struct send_report_args
*args
= THREAD_ARG(t
);
491 assert(args
!= NULL
);
492 struct ctrl_state
*ctrl_state
= args
->ctrl_state
;
493 assert(ctrl_state
!= NULL
);
494 struct pcc_state
*pcc_state
;
496 if (args
->pcc_id
== 0) {
497 for (int i
= 0; i
< MAX_PCC
; i
++) {
498 if (ctrl_state
->pcc
[i
]) {
499 pcep_pcc_send_report(ctrl_state
,
506 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, args
->pcc_id
);
507 pcep_pcc_send_report(ctrl_state
, pcc_state
, args
->path
);
513 int pcep_thread_get_pcep_session_callback(struct thread
*t
)
515 struct get_pcep_session_args
*args
= THREAD_ARG(t
);
516 assert(args
!= NULL
);
517 struct ctrl_state
*ctrl_state
= args
->ctrl_state
;
518 assert(ctrl_state
!= NULL
);
519 struct pcc_state
*pcc_state
;
521 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, args
->pcc_id
);
524 pcep_lib_copy_pcep_session(pcc_state
->sess
);
530 int pcep_thread_get_pcc_info_callback(struct thread
*t
)
532 struct pcep_pcc_info
*args
= THREAD_ARG(t
);
533 assert(args
!= NULL
);
534 struct ctrl_state
*ctrl_state
= args
->ctrl_state
;
535 assert(ctrl_state
!= NULL
);
537 pcep_pcc_copy_pcc_info(ctrl_state
->pcc
, args
);
542 /* ------------ Controller Thread Timer Handler ------------ */
544 int schedule_thread_timer_with_cb(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
,
548 struct thread
**thread
,
549 pcep_ctrl_thread_callback timer_cb
)
551 assert(thread
!= NULL
);
553 struct pcep_ctrl_timer_data
*data
;
555 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
556 data
->ctrl_state
= ctrl_state
;
557 data
->timer_type
= timer_type
;
558 data
->timeout_type
= timeout_type
;
559 data
->pcc_id
= pcc_id
;
560 data
->payload
= payload
;
562 thread_add_timer(ctrl_state
->self
, timer_cb
, (void *)data
, delay
,
568 int schedule_thread_timer(struct ctrl_state
*ctrl_state
, int pcc_id
,
569 enum pcep_ctrl_timer_type timer_type
,
570 enum pcep_ctrl_timeout_type timeout_type
,
571 uint32_t delay
, void *payload
, struct thread
**thread
)
573 return schedule_thread_timer_with_cb(ctrl_state
, pcc_id
, timer_type
,
574 timeout_type
, delay
, payload
,
575 thread
, pcep_thread_timer_handler
);
578 int pcep_thread_timer_handler(struct thread
*thread
)
581 struct pcep_ctrl_timer_data
*data
= THREAD_ARG(thread
);
582 assert(data
!= NULL
);
583 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
584 assert(ctrl_state
!= NULL
);
585 enum pcep_ctrl_timer_type timer_type
= data
->timer_type
;
586 enum pcep_ctrl_timeout_type timeout_type
= data
->timeout_type
;
587 int pcc_id
= data
->pcc_id
;
588 void *param
= data
->payload
;
589 XFREE(MTYPE_PCEP
, data
);
592 struct pcc_state
*pcc_state
= NULL
;
594 switch (timer_type
) {
595 case TM_RECONNECT_PCC
:
596 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
599 pcep_pcc_reconnect(ctrl_state
, pcc_state
);
602 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
605 pcep_pcc_timeout_handler(ctrl_state
, pcc_state
, timeout_type
,
608 case TM_CALCULATE_BEST_PCE
:
609 /* Previous best disconnect so new best should be synced */
610 ret
= pcep_pcc_timer_update_best_pce(ctrl_state
, pcc_id
);
612 case TM_SESSION_TIMEOUT_PCC
:
613 pcc_state
= pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
614 pcep_thread_remove_candidate_path_segments(ctrl_state
,
618 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
619 "Unknown controller timer triggered: %u", timer_type
);
626 int pcep_thread_pcep_event(struct thread
*thread
)
628 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
629 assert(data
!= NULL
);
630 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
631 pcep_event
*event
= data
->payload
;
632 XFREE(MTYPE_PCEP
, data
);
635 for (i
= 0; i
< MAX_PCC
; i
++) {
636 if (ctrl_state
->pcc
[i
]) {
637 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
638 if (pcc_state
->sess
!= event
->session
)
640 pcep_pcc_pcep_event_handler(ctrl_state
, pcc_state
,
645 destroy_pcep_event(event
);
650 /* ------------ Controller Thread Socket Functions ------------ */
652 int schedule_thread_socket(struct ctrl_state
*ctrl_state
, int pcc_id
,
653 enum pcep_ctrl_socket_type type
, bool is_read
,
654 void *payload
, int fd
, struct thread
**thread
,
655 pcep_ctrl_thread_callback socket_cb
)
657 assert(thread
!= NULL
);
659 struct pcep_ctrl_socket_data
*data
;
661 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
662 data
->ctrl_state
= ctrl_state
;
664 data
->is_read
= is_read
;
666 data
->pcc_id
= pcc_id
;
667 data
->payload
= payload
;
670 thread_add_read(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
673 thread_add_write(ctrl_state
->self
, socket_cb
, (void *)data
, fd
,
680 int pcep_thread_socket_write(void *fpt
, void **thread
, int fd
, void *payload
,
681 pcep_ctrl_thread_callback socket_cb
)
683 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
685 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, false,
686 payload
, fd
, (struct thread
**)thread
,
690 int pcep_thread_socket_read(void *fpt
, void **thread
, int fd
, void *payload
,
691 pcep_ctrl_thread_callback socket_cb
)
693 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
695 return schedule_thread_socket(ctrl_state
, 0, SOCK_PCEPLIB
, true,
696 payload
, fd
, (struct thread
**)thread
,
700 int pcep_thread_send_ctrl_event(void *fpt
, void *payload
,
701 pcep_ctrl_thread_callback cb
)
703 struct ctrl_state
*ctrl_state
= ((struct frr_pthread
*)fpt
)->data
;
705 return send_to_thread_with_cb(ctrl_state
, 0, EV_PCEPLIB_EVENT
, 0,
709 /* ------------ Controller Thread Event Handler ------------ */
711 int send_to_thread(struct ctrl_state
*ctrl_state
, int pcc_id
,
712 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
715 return send_to_thread_with_cb(ctrl_state
, pcc_id
, type
, sub_type
,
716 payload
, pcep_thread_event_handler
);
719 int send_to_thread_with_cb(struct ctrl_state
*ctrl_state
, int pcc_id
,
720 enum pcep_ctrl_event_type type
, uint32_t sub_type
,
721 void *payload
, pcep_ctrl_thread_callback event_cb
)
723 struct pcep_ctrl_event_data
*data
;
725 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
726 data
->ctrl_state
= ctrl_state
;
728 data
->sub_type
= sub_type
;
729 data
->pcc_id
= pcc_id
;
730 data
->payload
= payload
;
732 thread_add_event(ctrl_state
->self
, event_cb
, (void *)data
, 0, NULL
);
737 int pcep_thread_event_handler(struct thread
*thread
)
740 struct pcep_ctrl_event_data
*data
= THREAD_ARG(thread
);
741 assert(data
!= NULL
);
742 struct ctrl_state
*ctrl_state
= data
->ctrl_state
;
743 assert(ctrl_state
!= NULL
);
744 enum pcep_ctrl_event_type type
= data
->type
;
745 uint32_t sub_type
= data
->sub_type
;
746 int pcc_id
= data
->pcc_id
;
747 void *payload
= data
->payload
;
748 XFREE(MTYPE_PCEP
, data
);
752 /* Possible sub-type values */
753 enum pcep_pathd_event_type path_event_type
= PCEP_PATH_UNDEFINED
;
755 /* Possible payload values */
756 struct path
*path
= NULL
;
757 struct pcc_opts
*pcc_opts
= NULL
;
758 struct pce_opts
*pce_opts
= NULL
;
759 struct pcc_state
*pcc_state
= NULL
;
762 case EV_UPDATE_PCC_OPTS
:
763 assert(payload
!= NULL
);
764 pcc_opts
= (struct pcc_opts
*)payload
;
765 ret
= pcep_thread_event_update_pcc_options(ctrl_state
,
768 case EV_UPDATE_PCE_OPTS
:
769 assert(payload
!= NULL
);
770 pce_opts
= (struct pce_opts
*)payload
;
771 ret
= pcep_thread_event_update_pce_options(ctrl_state
, pcc_id
,
775 pce_opts
= (struct pce_opts
*)payload
;
776 ret
= pcep_thread_event_remove_pcc(ctrl_state
, pce_opts
);
778 ret
= pcep_pcc_multi_pce_remove_pcc(ctrl_state
,
783 assert(payload
!= NULL
);
784 path_event_type
= (enum pcep_pathd_event_type
)sub_type
;
785 path
= (struct path
*)payload
;
786 ret
= pcep_thread_event_pathd_event(ctrl_state
, path_event_type
,
790 assert(payload
!= NULL
);
791 path
= (struct path
*)payload
;
792 pcep_pcc_multi_pce_sync_path(ctrl_state
, pcc_id
,
794 pcep_thread_event_sync_path(ctrl_state
, pcc_id
, path
);
797 ret
= pcep_thread_event_sync_done(ctrl_state
, pcc_id
);
799 case EV_RESET_PCC_SESSION
:
800 pcc_state
= pcep_pcc_get_pcc_by_name(ctrl_state
->pcc
,
801 (const char *)payload
);
803 pcep_pcc_disable(ctrl_state
, pcc_state
);
804 ret
= pcep_pcc_enable(ctrl_state
, pcc_state
);
806 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
807 "Cannot reset state for PCE: %s",
808 (const char *)payload
);
812 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
813 "Unexpected event received in controller thread: %u",
821 int pcep_thread_event_update_pcc_options(struct ctrl_state
*ctrl_state
,
822 struct pcc_opts
*opts
)
824 assert(opts
!= NULL
);
825 if (ctrl_state
->pcc_opts
!= NULL
) {
826 XFREE(MTYPE_PCEP
, ctrl_state
->pcc_opts
);
828 ctrl_state
->pcc_opts
= opts
;
832 int pcep_thread_event_update_pce_options(struct ctrl_state
*ctrl_state
,
833 int pcc_id
, struct pce_opts
*pce_opts
)
835 if (!pce_opts
|| !ctrl_state
) {
838 struct pcc_state
*pcc_state
;
839 struct pcc_opts
*pcc_opts
;
842 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
, pce_opts
);
843 if (current_pcc_id
) {
845 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, current_pcc_id
);
847 pcc_state
= pcep_pcc_initialize(ctrl_state
,
848 get_next_id(ctrl_state
));
849 if (set_pcc_state(ctrl_state
, pcc_state
)) {
850 XFREE(MTYPE_PCEP
, pcc_state
);
855 /* Copy the pcc options to delegate it to the update function */
856 pcc_opts
= XCALLOC(MTYPE_PCEP
, sizeof(*pcc_opts
));
857 memcpy(pcc_opts
, ctrl_state
->pcc_opts
, sizeof(*pcc_opts
));
859 if (pcep_pcc_update(ctrl_state
, pcc_state
, pcc_opts
, pce_opts
)) {
860 flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE
,
861 "failed to update PCC configuration");
868 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state
*ctrl_state
,
872 struct pcc_state
*pcc_state
=
873 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
875 remove_pcc_state(ctrl_state
, pcc_state
);
876 pcep_pcc_finalize(ctrl_state
, pcc_state
);
882 int pcep_thread_event_remove_pcc_all(struct ctrl_state
*ctrl_state
)
884 assert(ctrl_state
!= NULL
);
886 for (int i
= 0; i
< MAX_PCC
; i
++) {
887 pcep_thread_event_remove_pcc_by_id(
889 pcep_pcc_get_pcc_id_by_idx(ctrl_state
->pcc
, i
));
894 int pcep_thread_event_remove_pcc(struct ctrl_state
*ctrl_state
,
895 struct pce_opts
*pce_opts
)
897 assert(ctrl_state
!= NULL
);
900 int pcc_id
= pcep_pcc_get_pcc_id_by_ip_port(ctrl_state
->pcc
,
903 pcep_thread_event_remove_pcc_by_id(ctrl_state
, pcc_id
);
907 XFREE(MTYPE_PCEP
, pce_opts
);
909 pcep_thread_event_remove_pcc_all(ctrl_state
);
915 int pcep_thread_event_sync_path(struct ctrl_state
*ctrl_state
, int pcc_id
,
918 struct pcc_state
*pcc_state
=
919 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
920 pcep_pcc_sync_path(ctrl_state
, pcc_state
, path
);
921 pcep_free_path(path
);
925 int pcep_thread_event_sync_done(struct ctrl_state
*ctrl_state
, int pcc_id
)
927 struct pcc_state
*pcc_state
=
928 pcep_pcc_get_pcc_by_id(ctrl_state
->pcc
, pcc_id
);
929 pcep_pcc_sync_done(ctrl_state
, pcc_state
);
933 int pcep_thread_event_pathd_event(struct ctrl_state
*ctrl_state
,
934 enum pcep_pathd_event_type type
,
939 for (i
= 0; i
< MAX_PCC
; i
++) {
940 if (ctrl_state
->pcc
[i
]) {
941 struct pcc_state
*pcc_state
= ctrl_state
->pcc
[i
];
942 pcep_pcc_pathd_event_handler(ctrl_state
, pcc_state
,
947 pcep_free_path(path
);
953 /* ------------ Main Thread Event Handler ------------ */
955 int send_to_main(struct ctrl_state
*ctrl_state
, int pcc_id
,
956 enum pcep_main_event_type type
, void *payload
)
958 struct pcep_main_event_data
*data
;
960 data
= XCALLOC(MTYPE_PCEP
, sizeof(*data
));
961 data
->handler
= ctrl_state
->main_event_handler
;
963 data
->pcc_id
= pcc_id
;
964 data
->payload
= payload
;
966 thread_add_event(ctrl_state
->main
, pcep_main_event_handler
,
967 (void *)data
, 0, NULL
);
971 int pcep_main_event_handler(struct thread
*thread
)
974 struct pcep_main_event_data
*data
= THREAD_ARG(thread
);
975 assert(data
!= NULL
);
976 pcep_main_event_handler_t handler
= data
->handler
;
977 enum pcep_main_event_type type
= data
->type
;
978 int pcc_id
= data
->pcc_id
;
979 void *payload
= data
->payload
;
980 XFREE(MTYPE_PCEP
, data
);
982 return handler(type
, pcc_id
, payload
);
986 /* ------------ Helper functions ------------ */
987 void set_ctrl_state(struct frr_pthread
*fpt
, struct ctrl_state
*ctrl_state
)
990 fpt
->data
= ctrl_state
;
993 struct ctrl_state
*get_ctrl_state(struct frr_pthread
*fpt
)
996 assert(fpt
->data
!= NULL
);
998 struct ctrl_state
*ctrl_state
;
999 ctrl_state
= (struct ctrl_state
*)fpt
->data
;
1000 assert(ctrl_state
!= NULL
);
1004 int get_next_id(struct ctrl_state
*ctrl_state
)
1006 return ++ctrl_state
->pcc_last_id
;
1009 int set_pcc_state(struct ctrl_state
*ctrl_state
, struct pcc_state
*pcc_state
)
1011 assert(ctrl_state
!= NULL
);
1012 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1014 int current_pcc_idx
= pcep_pcc_get_free_pcc_idx(ctrl_state
->pcc
);
1015 if (current_pcc_idx
>= 0) {
1016 ctrl_state
->pcc
[current_pcc_idx
] = pcc_state
;
1017 ctrl_state
->pcc_count
++;
1018 PCEP_DEBUG("added pce pcc_id (%d) idx (%d)",
1019 pcep_pcc_get_pcc_id(pcc_state
), current_pcc_idx
);
1022 PCEP_DEBUG("Max number of pce ");
1027 void remove_pcc_state(struct ctrl_state
*ctrl_state
,
1028 struct pcc_state
*pcc_state
)
1030 assert(ctrl_state
!= NULL
);
1031 assert(pcep_pcc_get_pcc_id(pcc_state
) != 0);
1034 idx
= pcep_pcc_get_pcc_idx_by_id(ctrl_state
->pcc
,
1035 pcep_pcc_get_pcc_id(pcc_state
));
1037 ctrl_state
->pcc
[idx
] = NULL
;
1038 ctrl_state
->pcc_count
--;
1039 PCEP_DEBUG("removed pce pcc_id (%d)",
1040 pcep_pcc_get_pcc_id(pcc_state
));
1044 uint32_t backoff_delay(uint32_t max
, uint32_t base
, uint32_t retry_count
)
1046 uint32_t a
= min(max
, base
* (1 << retry_count
));
1047 uint64_t r
= frr_weak_random(), m
= RAND_MAX
;
1048 uint32_t b
= (a
/ 2) + (r
* (a
/ 2)) / m
;
1052 const char *timer_type_name(enum pcep_ctrl_timer_type type
)
1057 case TM_RECONNECT_PCC
:
1058 return "RECONNECT_PCC";
1059 case TM_PCEPLIB_TIMER
:
1060 return "PCEPLIB_TIMER";
1068 const char *timeout_type_name(enum pcep_ctrl_timeout_type type
)
1073 case TO_COMPUTATION_REQUEST
:
1074 return "COMPUTATION_REQUEST";