]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_controller.c
pathd: add meaningful names to threads
[mirror_frr.git] / pathd / path_pcep_controller.c
1 /*
2 * Copyright (C) 2020 NetDEF, Inc.
3 *
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)
7 * any later version.
8 *
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
12 * more details.
13 *
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
17 */
18
19 #include <zebra.h>
20
21 #include "log.h"
22 #include "command.h"
23 #include "libfrr.h"
24 #include "printfrr.h"
25 #include "version.h"
26 #include "northbound.h"
27 #include "frr_pthread.h"
28 #include "jhash.h"
29 #include "network.h"
30
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"
38
39 #define MAX_RECONNECT_DELAY 120
40
41 #define min(a, b) \
42 ({ \
43 __typeof__(a) _a = (a); \
44 __typeof__(b) _b = (b); \
45 _a <= _b ? _a : _b; \
46 })
47
48
49 /* Event handling data structures */
50 enum pcep_ctrl_event_type {
51 EV_UPDATE_PCC_OPTS = 1,
52 EV_UPDATE_PCE_OPTS,
53 EV_REMOVE_PCC,
54 EV_PATHD_EVENT,
55 EV_SYNC_PATH,
56 EV_SYNC_DONE,
57 EV_PCEPLIB_EVENT,
58 EV_RESET_PCC_SESSION
59 };
60
61 struct pcep_ctrl_event_data {
62 struct ctrl_state *ctrl_state;
63 enum pcep_ctrl_event_type type;
64 uint32_t sub_type;
65 int pcc_id;
66 void *payload;
67 };
68
69 struct pcep_main_event_data {
70 pcep_main_event_handler_t handler;
71 int pcc_id;
72 enum pcep_main_event_type type;
73 void *payload;
74 };
75
76 /* Synchronous call arguments */
77
78 struct get_counters_args {
79 struct ctrl_state *ctrl_state;
80 int pcc_id;
81 struct counters_group *counters;
82 };
83
84 struct send_report_args {
85 struct ctrl_state *ctrl_state;
86 int pcc_id;
87 struct path *path;
88 };
89
90 struct get_pcep_session_args {
91 struct ctrl_state *ctrl_state;
92 int pcc_id;
93 pcep_session *pcep_session;
94 };
95
96 /* Internal Functions Called From Main Thread */
97 static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res);
98
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);
105
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);
118
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);
124
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,
128 void *payload);
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,
137 int pcc_id,
138 struct pce_opts *opts);
139 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state,
140 int pcc_id);
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,
147 int pcc_id);
148 static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
149 enum pcep_pathd_event_type type,
150 struct path *path);
151
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);
156
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);
168
169
170 /* ------------ API Functions Called from Main Thread ------------ */
171
172 int pcep_ctrl_initialize(struct thread_master *main_thread,
173 struct frr_pthread **fpt,
174 pcep_main_event_handler_t event_handler)
175 {
176 assert(fpt != NULL);
177
178 int ret = 0;
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,
183 };
184
185 PCEP_DEBUG("Initializing pcep module controller");
186
187 /* Create and start the FRR pthread */
188 *fpt = frr_pthread_new(&attr, "PCEP thread", "pcep_controller");
189 if (*fpt == NULL) {
190 flog_err(EC_PATH_SYSTEM_CALL,
191 "failed to initialize PCEP thread");
192 return 1;
193 }
194 ret = frr_pthread_run(*fpt, NULL);
195 if (ret < 0) {
196 flog_err(EC_PATH_SYSTEM_CALL, "failed to create PCEP thread");
197 return ret;
198 }
199 frr_pthread_wait_running(*fpt);
200
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;
213
214 /* Keep the state reference for events */
215 set_ctrl_state(*fpt, ctrl_state);
216
217 return ret;
218 }
219
220 int pcep_ctrl_finalize(struct frr_pthread **fpt)
221 {
222 assert(fpt != NULL);
223
224 int ret = 0;
225
226 PCEP_DEBUG("Finalizing pcep module controller");
227
228 if (*fpt != NULL) {
229 frr_pthread_stop(*fpt, NULL);
230 *fpt = NULL;
231 }
232
233 return ret;
234 }
235
236 int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt, struct pcc_opts *opts)
237 {
238 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
239 return send_to_thread(ctrl_state, 0, EV_UPDATE_PCC_OPTS, 0, opts);
240 }
241
242 int pcep_ctrl_update_pce_options(struct frr_pthread *fpt, struct pce_opts *opts)
243 {
244 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
245 return send_to_thread(ctrl_state, 0, EV_UPDATE_PCE_OPTS, 0, opts);
246 }
247
248 int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct pce_opts *pce_opts)
249 {
250 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
251 return send_to_thread(ctrl_state, 0, EV_REMOVE_PCC, 0, pce_opts);
252 }
253
254 int pcep_ctrl_reset_pcc_session(struct frr_pthread *fpt, char *pce_name)
255 {
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);
258 }
259
260 int pcep_ctrl_pathd_event(struct frr_pthread *fpt,
261 enum pcep_pathd_event_type type, struct path *path)
262 {
263 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
264 return send_to_thread(ctrl_state, 0, EV_PATHD_EVENT, type, path);
265 }
266
267 int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path)
268 {
269 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
270 return send_to_thread(ctrl_state, pcc_id, EV_SYNC_PATH, 0, path);
271 }
272
273 int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id)
274 {
275 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
276 return send_to_thread(ctrl_state, pcc_id, EV_SYNC_DONE, 0, NULL);
277 }
278
279 struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt,
280 int pcc_id)
281 {
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,
286 &args, 0);
287 return args.counters;
288 }
289
290 pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id)
291 {
292 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
293 struct get_pcep_session_args args = {.ctrl_state = ctrl_state,
294 .pcc_id = pcc_id,
295 .pcep_session = NULL};
296 thread_execute(ctrl_state->self, pcep_thread_get_pcep_session_callback,
297 &args, 0);
298 return args.pcep_session;
299 }
300
301 struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
302 const char *pce_name)
303 {
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,
309 args, 0);
310
311 return args;
312 }
313
314 void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
315 struct path *path)
316 {
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,
322 &args, 0);
323 }
324
325 /* ------------ Internal Functions Called from Main Thread ------------ */
326
327 int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
328 {
329 thread_add_event(fpt->master, pcep_thread_finish_event_handler,
330 (void *)fpt, 0, NULL);
331 pthread_join(fpt->thread, res);
332
333 return 0;
334 }
335
336
337 /* ------------ API Functions Called From Controller Thread ------------ */
338
339 void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id)
340 {
341 send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_START_SYNC, NULL);
342 }
343
344 void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
345 struct path *path)
346 {
347 send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
348 path);
349 }
350
351 void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state,
352 struct pcc_state *pcc_state)
353 {
354 if (!pcc_state)
355 return;
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",
359 originator);
360 send_to_main(ctrl_state, pcep_pcc_get_pcc_id(pcc_state),
361 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP, originator);
362 }
363
364 void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state,
365 int pcc_id, int delay,
366 struct thread **thread)
367 {
368
369 schedule_thread_timer(ctrl_state, pcc_id, TM_CALCULATE_BEST_PCE,
370 TO_UNDEFINED, delay, NULL, thread);
371 }
372
373 void pcep_thread_cancel_timer(struct thread **thread)
374 {
375 if (thread == NULL || *thread == NULL) {
376 return;
377 }
378
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));
382 if (data != NULL) {
383 XFREE(MTYPE_PCEP, data);
384 }
385
386 if ((*thread)->master->owner == pthread_self()) {
387 thread_cancel(thread);
388 } else {
389 thread_cancel_async((*thread)->master, thread, NULL);
390 }
391 }
392
393 void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id,
394 int retry_count, struct thread **thread)
395 {
396 uint32_t delay = backoff_delay(MAX_RECONNECT_DELAY, 1, retry_count);
397 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay,
398 retry_count);
399 schedule_thread_timer(ctrl_state, pcc_id, TM_RECONNECT_PCC,
400 TO_UNDEFINED, delay, NULL, thread);
401 }
402
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)
407 {
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);
414 }
415
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)
420 {
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,
424 timer_cb);
425 }
426
427 void pcep_thread_schedule_session_timeout(struct ctrl_state *ctrl_state,
428 int pcc_id, int delay,
429 struct thread **thread)
430 {
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);
434 }
435
436 int pcep_thread_pcc_count(struct ctrl_state *ctrl_state)
437 {
438 if (ctrl_state == NULL) {
439 return 0;
440 }
441
442 return ctrl_state->pcc_count;
443 }
444
445 /* ------------ Internal Functions Called From Controller Thread ------------ */
446
447 int pcep_thread_finish_event_handler(struct thread *thread)
448 {
449 int i;
450 struct frr_pthread *fpt = THREAD_ARG(thread);
451 struct ctrl_state *ctrl_state = fpt->data;
452
453 assert(ctrl_state != NULL);
454
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;
459 }
460 }
461
462 XFREE(MTYPE_PCEP, ctrl_state->pcc_opts);
463 XFREE(MTYPE_PCEP, ctrl_state);
464 fpt->data = NULL;
465
466 atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
467 return 0;
468 }
469
470 int pcep_thread_get_counters_callback(struct thread *t)
471 {
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;
477
478 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
479 if (pcc_state) {
480 args->counters = pcep_lib_copy_counters(pcc_state->sess);
481 } else {
482 args->counters = NULL;
483 }
484
485 return 0;
486 }
487
488 int pcep_thread_send_report_callback(struct thread *t)
489 {
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;
495
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,
500 ctrl_state->pcc[i],
501 args->path);
502 }
503 }
504 } else {
505 pcc_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);
508 }
509
510 return 0;
511 }
512
513 int pcep_thread_get_pcep_session_callback(struct thread *t)
514 {
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;
520
521 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
522 if (pcc_state) {
523 args->pcep_session =
524 pcep_lib_copy_pcep_session(pcc_state->sess);
525 }
526
527 return 0;
528 }
529
530 int pcep_thread_get_pcc_info_callback(struct thread *t)
531 {
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);
536
537 pcep_pcc_copy_pcc_info(ctrl_state->pcc, args);
538
539 return 0;
540 }
541
542 /* ------------ Controller Thread Timer Handler ------------ */
543
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)
550 {
551 assert(thread != NULL);
552
553 struct pcep_ctrl_timer_data *data;
554
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;
561
562 thread_add_timer(ctrl_state->self, timer_cb, (void *)data, delay,
563 thread);
564
565 return 0;
566 }
567
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)
572 {
573 return schedule_thread_timer_with_cb(ctrl_state, pcc_id, timer_type,
574 timeout_type, delay, payload,
575 thread, pcep_thread_timer_handler);
576 }
577
578 int pcep_thread_timer_handler(struct thread *thread)
579 {
580 /* data unpacking */
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);
590
591 int ret = 0;
592 struct pcc_state *pcc_state = NULL;
593
594 switch (timer_type) {
595 case TM_RECONNECT_PCC:
596 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
597 if (!pcc_state)
598 return ret;
599 pcep_pcc_reconnect(ctrl_state, pcc_state);
600 break;
601 case TM_TIMEOUT:
602 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
603 if (!pcc_state)
604 return ret;
605 pcep_pcc_timeout_handler(ctrl_state, pcc_state, timeout_type,
606 param);
607 break;
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);
611 break;
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,
615 pcc_state);
616 break;
617 default:
618 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
619 "Unknown controller timer triggered: %u", timer_type);
620 break;
621 }
622
623 return ret;
624 }
625
626 int pcep_thread_pcep_event(struct thread *thread)
627 {
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);
633 int i;
634
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)
639 continue;
640 pcep_pcc_pcep_event_handler(ctrl_state, pcc_state,
641 event);
642 break;
643 }
644 }
645 destroy_pcep_event(event);
646
647 return 0;
648 }
649
650 /* ------------ Controller Thread Socket Functions ------------ */
651
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)
656 {
657 assert(thread != NULL);
658
659 struct pcep_ctrl_socket_data *data;
660
661 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
662 data->ctrl_state = ctrl_state;
663 data->type = type;
664 data->is_read = is_read;
665 data->fd = fd;
666 data->pcc_id = pcc_id;
667 data->payload = payload;
668
669 if (is_read) {
670 thread_add_read(ctrl_state->self, socket_cb, (void *)data, fd,
671 thread);
672 } else {
673 thread_add_write(ctrl_state->self, socket_cb, (void *)data, fd,
674 thread);
675 }
676
677 return 0;
678 }
679
680 int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload,
681 pcep_ctrl_thread_callback socket_cb)
682 {
683 struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
684
685 return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, false,
686 payload, fd, (struct thread **)thread,
687 socket_cb);
688 }
689
690 int pcep_thread_socket_read(void *fpt, void **thread, int fd, void *payload,
691 pcep_ctrl_thread_callback socket_cb)
692 {
693 struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
694
695 return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, true,
696 payload, fd, (struct thread **)thread,
697 socket_cb);
698 }
699
700 int pcep_thread_send_ctrl_event(void *fpt, void *payload,
701 pcep_ctrl_thread_callback cb)
702 {
703 struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
704
705 return send_to_thread_with_cb(ctrl_state, 0, EV_PCEPLIB_EVENT, 0,
706 payload, cb);
707 }
708
709 /* ------------ Controller Thread Event Handler ------------ */
710
711 int send_to_thread(struct ctrl_state *ctrl_state, int pcc_id,
712 enum pcep_ctrl_event_type type, uint32_t sub_type,
713 void *payload)
714 {
715 return send_to_thread_with_cb(ctrl_state, pcc_id, type, sub_type,
716 payload, pcep_thread_event_handler);
717 }
718
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)
722 {
723 struct pcep_ctrl_event_data *data;
724
725 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
726 data->ctrl_state = ctrl_state;
727 data->type = type;
728 data->sub_type = sub_type;
729 data->pcc_id = pcc_id;
730 data->payload = payload;
731
732 thread_add_event(ctrl_state->self, event_cb, (void *)data, 0, NULL);
733
734 return 0;
735 }
736
737 int pcep_thread_event_handler(struct thread *thread)
738 {
739 /* data unpacking */
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);
749
750 int ret = 0;
751
752 /* Possible sub-type values */
753 enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED;
754
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;
760
761 switch (type) {
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,
766 pcc_opts);
767 break;
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,
772 pce_opts);
773 break;
774 case EV_REMOVE_PCC:
775 pce_opts = (struct pce_opts *)payload;
776 ret = pcep_thread_event_remove_pcc(ctrl_state, pce_opts);
777 if (ret == 0) {
778 ret = pcep_pcc_multi_pce_remove_pcc(ctrl_state,
779 ctrl_state->pcc);
780 }
781 break;
782 case EV_PATHD_EVENT:
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,
787 path);
788 break;
789 case EV_SYNC_PATH:
790 assert(payload != NULL);
791 path = (struct path *)payload;
792 pcep_pcc_multi_pce_sync_path(ctrl_state, pcc_id,
793 ctrl_state->pcc);
794 pcep_thread_event_sync_path(ctrl_state, pcc_id, path);
795 break;
796 case EV_SYNC_DONE:
797 ret = pcep_thread_event_sync_done(ctrl_state, pcc_id);
798 break;
799 case EV_RESET_PCC_SESSION:
800 pcc_state = pcep_pcc_get_pcc_by_name(ctrl_state->pcc,
801 (const char *)payload);
802 if (pcc_state) {
803 pcep_pcc_disable(ctrl_state, pcc_state);
804 ret = pcep_pcc_enable(ctrl_state, pcc_state);
805 } else {
806 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
807 "Cannot reset state for PCE: %s",
808 (const char *)payload);
809 }
810 break;
811 default:
812 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
813 "Unexpected event received in controller thread: %u",
814 type);
815 break;
816 }
817
818 return ret;
819 }
820
821 int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state,
822 struct pcc_opts *opts)
823 {
824 assert(opts != NULL);
825 if (ctrl_state->pcc_opts != NULL) {
826 XFREE(MTYPE_PCEP, ctrl_state->pcc_opts);
827 }
828 ctrl_state->pcc_opts = opts;
829 return 0;
830 }
831
832 int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state,
833 int pcc_id, struct pce_opts *pce_opts)
834 {
835 if (!pce_opts || !ctrl_state) {
836 return 0;
837 }
838 struct pcc_state *pcc_state;
839 struct pcc_opts *pcc_opts;
840
841 int current_pcc_id =
842 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, pce_opts);
843 if (current_pcc_id) {
844 pcc_state =
845 pcep_pcc_get_pcc_by_id(ctrl_state->pcc, current_pcc_id);
846 } else {
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);
851 return 0;
852 }
853 }
854
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));
858
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");
862 }
863
864
865 return 0;
866 }
867
868 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state,
869 int pcc_id)
870 {
871 if (pcc_id) {
872 struct pcc_state *pcc_state =
873 pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
874 if (pcc_state) {
875 remove_pcc_state(ctrl_state, pcc_state);
876 pcep_pcc_finalize(ctrl_state, pcc_state);
877 }
878 }
879 return 0;
880 }
881
882 int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state)
883 {
884 assert(ctrl_state != NULL);
885
886 for (int i = 0; i < MAX_PCC; i++) {
887 pcep_thread_event_remove_pcc_by_id(
888 ctrl_state,
889 pcep_pcc_get_pcc_id_by_idx(ctrl_state->pcc, i));
890 }
891 return 0;
892 }
893
894 int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state,
895 struct pce_opts *pce_opts)
896 {
897 assert(ctrl_state != NULL);
898
899 if (pce_opts) {
900 int pcc_id = pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc,
901 pce_opts);
902 if (pcc_id) {
903 pcep_thread_event_remove_pcc_by_id(ctrl_state, pcc_id);
904 } else {
905 return -1;
906 }
907 XFREE(MTYPE_PCEP, pce_opts);
908 } else {
909 pcep_thread_event_remove_pcc_all(ctrl_state);
910 }
911
912 return 0;
913 }
914
915 int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
916 struct path *path)
917 {
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);
922 return 0;
923 }
924
925 int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, int pcc_id)
926 {
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);
930 return 0;
931 }
932
933 int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
934 enum pcep_pathd_event_type type,
935 struct path *path)
936 {
937 int i;
938
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,
943 type, path);
944 }
945 }
946
947 pcep_free_path(path);
948
949 return 0;
950 }
951
952
953 /* ------------ Main Thread Event Handler ------------ */
954
955 int send_to_main(struct ctrl_state *ctrl_state, int pcc_id,
956 enum pcep_main_event_type type, void *payload)
957 {
958 struct pcep_main_event_data *data;
959
960 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
961 data->handler = ctrl_state->main_event_handler;
962 data->type = type;
963 data->pcc_id = pcc_id;
964 data->payload = payload;
965
966 thread_add_event(ctrl_state->main, pcep_main_event_handler,
967 (void *)data, 0, NULL);
968 return 0;
969 }
970
971 int pcep_main_event_handler(struct thread *thread)
972 {
973 /* data unpacking */
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);
981
982 return handler(type, pcc_id, payload);
983 }
984
985
986 /* ------------ Helper functions ------------ */
987 void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state)
988 {
989 assert(fpt != NULL);
990 fpt->data = ctrl_state;
991 }
992
993 struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt)
994 {
995 assert(fpt != NULL);
996 assert(fpt->data != NULL);
997
998 struct ctrl_state *ctrl_state;
999 ctrl_state = (struct ctrl_state *)fpt->data;
1000 assert(ctrl_state != NULL);
1001 return ctrl_state;
1002 }
1003
1004 int get_next_id(struct ctrl_state *ctrl_state)
1005 {
1006 return ++ctrl_state->pcc_last_id;
1007 }
1008
1009 int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
1010 {
1011 assert(ctrl_state != NULL);
1012 assert(pcep_pcc_get_pcc_id(pcc_state) != 0);
1013
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);
1020 return 0;
1021 } else {
1022 PCEP_DEBUG("Max number of pce ");
1023 return 1;
1024 }
1025 }
1026
1027 void remove_pcc_state(struct ctrl_state *ctrl_state,
1028 struct pcc_state *pcc_state)
1029 {
1030 assert(ctrl_state != NULL);
1031 assert(pcep_pcc_get_pcc_id(pcc_state) != 0);
1032
1033 int idx = 0;
1034 idx = pcep_pcc_get_pcc_idx_by_id(ctrl_state->pcc,
1035 pcep_pcc_get_pcc_id(pcc_state));
1036 if (idx != -1) {
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));
1041 }
1042 }
1043
1044 uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t retry_count)
1045 {
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;
1049 return b;
1050 }
1051
1052 const char *timer_type_name(enum pcep_ctrl_timer_type type)
1053 {
1054 switch (type) {
1055 case TM_UNDEFINED:
1056 return "UNDEFINED";
1057 case TM_RECONNECT_PCC:
1058 return "RECONNECT_PCC";
1059 case TM_PCEPLIB_TIMER:
1060 return "PCEPLIB_TIMER";
1061 case TM_TIMEOUT:
1062 return "TIMEOUT";
1063 default:
1064 return "UNKNOWN";
1065 }
1066 };
1067
1068 const char *timeout_type_name(enum pcep_ctrl_timeout_type type)
1069 {
1070 switch (type) {
1071 case TO_UNDEFINED:
1072 return "UNDEFINED";
1073 case TO_COMPUTATION_REQUEST:
1074 return "COMPUTATION_REQUEST";
1075 default:
1076 return "UNKNOWN";
1077 }
1078 }