]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_controller.c
Merge pull request #8441 from mjstapp/fix_topo_pylint1
[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 "lib/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 EV_SEND_REPORT,
60 EV_PATH_REFINED
61 };
62
63 struct pcep_ctrl_event_data {
64 struct ctrl_state *ctrl_state;
65 enum pcep_ctrl_event_type type;
66 uint32_t sub_type;
67 int pcc_id;
68 void *payload;
69 };
70
71 struct pcep_main_event_data {
72 pcep_main_event_handler_t handler;
73 int pcc_id;
74 enum pcep_main_event_type type;
75 void *payload;
76 };
77
78 struct pcep_refine_path_event_data {
79 struct ctrl_state *ctrl_state;
80 int pcc_id;
81 pcep_refine_callback_t continue_lsp_update_handler;
82 struct path *path;
83 void *payload;
84 };
85
86 /* Synchronous call arguments */
87
88 struct get_counters_args {
89 struct ctrl_state *ctrl_state;
90 int pcc_id;
91 struct counters_group *counters;
92 };
93
94 struct get_pcep_session_args {
95 struct ctrl_state *ctrl_state;
96 int pcc_id;
97 pcep_session *pcep_session;
98 };
99
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);
103
104 /* Internal Functions Called From Controller Thread */
105 static int pcep_thread_finish_event_handler(struct thread *thread);
106
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);
119
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);
125
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,
129 void *payload);
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,
138 int pcc_id,
139 struct pce_opts *opts);
140 static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state,
141 int pcc_id);
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,
148 int pcc_id);
149 static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
150 enum pcep_pathd_event_type type,
151 struct path *path);
152 static void
153 pcep_thread_path_refined_event(struct ctrl_state *ctrl_state,
154 struct pcep_refine_path_event_data *data);
155
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);
160
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);
172
173
174 /* ------------ API Functions Called from Main Thread ------------ */
175
176 int pcep_ctrl_initialize(struct thread_master *main_thread,
177 struct frr_pthread **fpt,
178 pcep_main_event_handler_t event_handler)
179 {
180 assert(fpt != NULL);
181
182 int ret = 0;
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,
187 };
188
189 PCEP_DEBUG("Initializing pcep module controller");
190
191 /* Create and start the FRR pthread */
192 *fpt = frr_pthread_new(&attr, "PCEP thread", "pcep_controller");
193 if (*fpt == NULL) {
194 flog_err(EC_PATH_SYSTEM_CALL,
195 "failed to initialize PCEP thread");
196 return 1;
197 }
198 ret = frr_pthread_run(*fpt, NULL);
199 if (ret < 0) {
200 flog_err(EC_PATH_SYSTEM_CALL, "failed to create PCEP thread");
201 return ret;
202 }
203 frr_pthread_wait_running(*fpt);
204
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;
217
218 /* Keep the state reference for events */
219 set_ctrl_state(*fpt, ctrl_state);
220
221 return ret;
222 }
223
224 int pcep_ctrl_finalize(struct frr_pthread **fpt)
225 {
226 assert(fpt != NULL);
227
228 int ret = 0;
229
230 PCEP_DEBUG("Finalizing pcep module controller");
231
232 if (*fpt != NULL) {
233 frr_pthread_stop(*fpt, NULL);
234 *fpt = NULL;
235 }
236
237 return ret;
238 }
239
240 int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt, struct pcc_opts *opts)
241 {
242 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
243 return send_to_thread(ctrl_state, 0, EV_UPDATE_PCC_OPTS, 0, opts);
244 }
245
246 int pcep_ctrl_update_pce_options(struct frr_pthread *fpt, struct pce_opts *opts)
247 {
248 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
249 return send_to_thread(ctrl_state, 0, EV_UPDATE_PCE_OPTS, 0, opts);
250 }
251
252 int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct pce_opts *pce_opts)
253 {
254 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
255 return send_to_thread(ctrl_state, 0, EV_REMOVE_PCC, 0, pce_opts);
256 }
257
258 int pcep_ctrl_reset_pcc_session(struct frr_pthread *fpt, char *pce_name)
259 {
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);
262 }
263
264 int pcep_ctrl_pathd_event(struct frr_pthread *fpt,
265 enum pcep_pathd_event_type type, struct path *path)
266 {
267 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
268 return send_to_thread(ctrl_state, 0, EV_PATHD_EVENT, type, path);
269 }
270
271 int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path)
272 {
273 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
274 return send_to_thread(ctrl_state, pcc_id, EV_SYNC_PATH, 0, path);
275 }
276
277 int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id)
278 {
279 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
280 return send_to_thread(ctrl_state, pcc_id, EV_SYNC_DONE, 0, NULL);
281 }
282
283 struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt,
284 int pcc_id)
285 {
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);
290 if (pcc_state) {
291 counters = pcep_lib_copy_counters(pcc_state->sess);
292 }
293 return counters;
294 }
295
296 pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id)
297 {
298 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
299 struct pcc_state *pcc_state;
300 pcep_session *session = NULL;
301
302 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
303 if (pcc_state) {
304 session = pcep_lib_copy_pcep_session(pcc_state->sess);
305 }
306 return session;
307 }
308
309 struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
310 const char *pce_name)
311 {
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);
317 }
318
319 return pcc_info;
320 }
321
322 int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
323 struct path *path, bool is_stable)
324 {
325 struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
326 return send_to_thread(ctrl_state, pcc_id, EV_SEND_REPORT, is_stable,
327 path);
328 }
329
330
331 /* ------------ Internal Functions Called from Main Thread ------------ */
332
333 int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
334 {
335 thread_add_event(fpt->master, pcep_thread_finish_event_handler,
336 (void *)fpt, 0, NULL);
337 pthread_join(fpt->thread, res);
338
339 return 0;
340 }
341
342 int pcep_refine_path_event_cb(struct thread *thread)
343 {
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;
350
351
352 path_pcep_refine_path(path);
353 return send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data);
354 }
355
356
357 /* ------------ API Functions Called From Controller Thread ------------ */
358
359 void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id)
360 {
361 send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_START_SYNC, NULL);
362 }
363
364 void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
365 struct path *path)
366 {
367 send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
368 path);
369 }
370
371 void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state,
372 struct pcc_state *pcc_state)
373 {
374 if (!pcc_state)
375 return;
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",
379 originator);
380 send_to_main(ctrl_state, pcep_pcc_get_pcc_id(pcc_state),
381 PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP, originator);
382 }
383
384 void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state,
385 int pcc_id, int delay,
386 struct thread **thread)
387 {
388
389 schedule_thread_timer(ctrl_state, pcc_id, TM_CALCULATE_BEST_PCE,
390 TO_UNDEFINED, delay, NULL, thread);
391 }
392
393 void pcep_thread_cancel_timer(struct thread **thread)
394 {
395 if (thread == NULL || *thread == NULL) {
396 return;
397 }
398
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));
402 if (data != NULL) {
403 XFREE(MTYPE_PCEP, data);
404 }
405
406 if ((*thread)->master->owner == pthread_self()) {
407 thread_cancel(thread);
408 } else {
409 thread_cancel_async((*thread)->master, thread, NULL);
410 }
411 }
412
413 void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id,
414 int retry_count, struct thread **thread)
415 {
416 uint32_t delay = backoff_delay(MAX_RECONNECT_DELAY, 1, retry_count);
417 PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay,
418 retry_count);
419 schedule_thread_timer(ctrl_state, pcc_id, TM_RECONNECT_PCC,
420 TO_UNDEFINED, delay, NULL, thread);
421 }
422
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)
427 {
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);
434 }
435
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)
440 {
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,
444 timer_cb);
445 }
446
447 void pcep_thread_schedule_session_timeout(struct ctrl_state *ctrl_state,
448 int pcc_id, int delay,
449 struct thread **thread)
450 {
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);
454 }
455
456 int pcep_thread_pcc_count(struct ctrl_state *ctrl_state)
457 {
458 if (ctrl_state == NULL) {
459 return 0;
460 }
461
462 return ctrl_state->pcc_count;
463 }
464
465 int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id,
466 pcep_refine_callback_t cb, struct path *path,
467 void *payload)
468 {
469 struct pcep_refine_path_event_data *data;
470
471 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
472 data->ctrl_state = ctrl_state;
473 data->path = path;
474 data->pcc_id = pcc_id;
475 data->continue_lsp_update_handler = cb;
476 data->payload = payload;
477
478 thread_add_event(ctrl_state->main, pcep_refine_path_event_cb,
479 (void *)data, 0, NULL);
480 return 0;
481 }
482
483 void pcep_thread_path_refined_event(struct ctrl_state *ctrl_state,
484 struct pcep_refine_path_event_data *data)
485 {
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);
494
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);
497 }
498
499
500 /* ------------ Internal Functions Called From Controller Thread ------------ */
501
502 int pcep_thread_finish_event_handler(struct thread *thread)
503 {
504 int i;
505 struct frr_pthread *fpt = THREAD_ARG(thread);
506 struct ctrl_state *ctrl_state = fpt->data;
507
508 assert(ctrl_state != NULL);
509
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;
514 }
515 }
516
517 XFREE(MTYPE_PCEP, ctrl_state->pcc_opts);
518 XFREE(MTYPE_PCEP, ctrl_state);
519 fpt->data = NULL;
520
521 atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
522 return 0;
523 }
524
525 /* ------------ Controller Thread Timer Handler ------------ */
526
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)
533 {
534 assert(thread != NULL);
535
536 struct pcep_ctrl_timer_data *data;
537
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;
544
545 thread_add_timer(ctrl_state->self, timer_cb, (void *)data, delay,
546 thread);
547
548 return 0;
549 }
550
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)
555 {
556 return schedule_thread_timer_with_cb(ctrl_state, pcc_id, timer_type,
557 timeout_type, delay, payload,
558 thread, pcep_thread_timer_handler);
559 }
560
561 int pcep_thread_timer_handler(struct thread *thread)
562 {
563 /* data unpacking */
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);
573
574 int ret = 0;
575 struct pcc_state *pcc_state = NULL;
576
577 switch (timer_type) {
578 case TM_RECONNECT_PCC:
579 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
580 if (!pcc_state)
581 return ret;
582 pcep_pcc_reconnect(ctrl_state, pcc_state);
583 break;
584 case TM_TIMEOUT:
585 pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
586 if (!pcc_state)
587 return ret;
588 pcep_pcc_timeout_handler(ctrl_state, pcc_state, timeout_type,
589 param);
590 break;
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);
594 break;
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,
598 pcc_state);
599 break;
600 default:
601 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
602 "Unknown controller timer triggered: %u", timer_type);
603 break;
604 }
605
606 return ret;
607 }
608
609 int pcep_thread_pcep_event(struct thread *thread)
610 {
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);
616 int i;
617
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)
622 continue;
623 pcep_pcc_pcep_event_handler(ctrl_state, pcc_state,
624 event);
625 break;
626 }
627 }
628 destroy_pcep_event(event);
629
630 return 0;
631 }
632
633 /* ------------ Controller Thread Socket Functions ------------ */
634
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)
639 {
640 assert(thread != NULL);
641
642 struct pcep_ctrl_socket_data *data;
643
644 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
645 data->ctrl_state = ctrl_state;
646 data->type = type;
647 data->is_read = is_read;
648 data->fd = fd;
649 data->pcc_id = pcc_id;
650 data->payload = payload;
651
652 if (is_read) {
653 thread_add_read(ctrl_state->self, socket_cb, (void *)data, fd,
654 thread);
655 } else {
656 thread_add_write(ctrl_state->self, socket_cb, (void *)data, fd,
657 thread);
658 }
659
660 return 0;
661 }
662
663 int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload,
664 pcep_ctrl_thread_callback socket_cb)
665 {
666 struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
667
668 return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, false,
669 payload, fd, (struct thread **)thread,
670 socket_cb);
671 }
672
673 int pcep_thread_socket_read(void *fpt, void **thread, int fd, void *payload,
674 pcep_ctrl_thread_callback socket_cb)
675 {
676 struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
677
678 return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, true,
679 payload, fd, (struct thread **)thread,
680 socket_cb);
681 }
682
683 int pcep_thread_send_ctrl_event(void *fpt, void *payload,
684 pcep_ctrl_thread_callback cb)
685 {
686 struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data;
687
688 return send_to_thread_with_cb(ctrl_state, 0, EV_PCEPLIB_EVENT, 0,
689 payload, cb);
690 }
691
692 /* ------------ Controller Thread Event Handler ------------ */
693
694 int send_to_thread(struct ctrl_state *ctrl_state, int pcc_id,
695 enum pcep_ctrl_event_type type, uint32_t sub_type,
696 void *payload)
697 {
698 return send_to_thread_with_cb(ctrl_state, pcc_id, type, sub_type,
699 payload, pcep_thread_event_handler);
700 }
701
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)
705 {
706 struct pcep_ctrl_event_data *data;
707
708 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
709 data->ctrl_state = ctrl_state;
710 data->type = type;
711 data->sub_type = sub_type;
712 data->pcc_id = pcc_id;
713 data->payload = payload;
714
715 thread_add_event(ctrl_state->self, event_cb, (void *)data, 0, NULL);
716
717 return 0;
718 }
719
720 int pcep_thread_event_handler(struct thread *thread)
721 {
722 /* data unpacking */
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);
732
733 int ret = 0;
734
735 /* Possible sub-type values */
736 enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED;
737
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;
744
745 struct path *path_copy = NULL;
746
747 switch (type) {
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,
752 pcc_opts);
753 break;
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,
758 pce_opts);
759 break;
760 case EV_REMOVE_PCC:
761 pce_opts = (struct pce_opts *)payload;
762 ret = pcep_thread_event_remove_pcc(ctrl_state, pce_opts);
763 if (ret == 0) {
764 ret = pcep_pcc_multi_pce_remove_pcc(ctrl_state,
765 ctrl_state->pcc);
766 }
767 break;
768 case EV_PATHD_EVENT:
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,
773 path);
774 break;
775 case EV_SYNC_PATH:
776 assert(payload != NULL);
777 path = (struct path *)payload;
778 pcep_pcc_multi_pce_sync_path(ctrl_state, pcc_id,
779 ctrl_state->pcc);
780 pcep_thread_event_sync_path(ctrl_state, pcc_id, path);
781 break;
782 case EV_SYNC_DONE:
783 ret = pcep_thread_event_sync_done(ctrl_state, pcc_id);
784 break;
785 case EV_RESET_PCC_SESSION:
786 pcc_state = pcep_pcc_get_pcc_by_name(ctrl_state->pcc,
787 (const char *)payload);
788 if (pcc_state) {
789 pcep_pcc_disable(ctrl_state, pcc_state);
790 ret = pcep_pcc_enable(ctrl_state, pcc_state);
791 } else {
792 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
793 "Cannot reset state for PCE: %s",
794 (const char *)payload);
795 }
796 break;
797 case EV_SEND_REPORT:
798 assert(payload != NULL);
799 path = (struct path *)payload;
800 if (pcc_id == 0) {
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);
807 }
808 }
809 } else {
810 pcc_state =
811 pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
812 pcep_pcc_send_report(ctrl_state, pcc_state, path,
813 (bool)sub_type);
814 }
815 break;
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);
820 break;
821 default:
822 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
823 "Unexpected event received in controller thread: %u",
824 type);
825 break;
826 }
827
828 return ret;
829 }
830
831 int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state,
832 struct pcc_opts *opts)
833 {
834 assert(opts != NULL);
835 if (ctrl_state->pcc_opts != NULL) {
836 XFREE(MTYPE_PCEP, ctrl_state->pcc_opts);
837 }
838 ctrl_state->pcc_opts = opts;
839 return 0;
840 }
841
842 int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state,
843 int pcc_id, struct pce_opts *pce_opts)
844 {
845 if (!pce_opts || !ctrl_state) {
846 return 0;
847 }
848 struct pcc_state *pcc_state;
849 struct pcc_opts *pcc_opts;
850
851 int current_pcc_id =
852 pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, pce_opts);
853 if (current_pcc_id) {
854 pcc_state =
855 pcep_pcc_get_pcc_by_id(ctrl_state->pcc, current_pcc_id);
856 } else {
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);
861 return 0;
862 }
863 }
864
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));
868
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");
872 }
873
874
875 return 0;
876 }
877
878 int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state,
879 int pcc_id)
880 {
881 if (pcc_id) {
882 struct pcc_state *pcc_state =
883 pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
884 if (pcc_state) {
885 remove_pcc_state(ctrl_state, pcc_state);
886 pcep_pcc_finalize(ctrl_state, pcc_state);
887 }
888 }
889 return 0;
890 }
891
892 int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state)
893 {
894 assert(ctrl_state != NULL);
895
896 for (int i = 0; i < MAX_PCC; i++) {
897 pcep_thread_event_remove_pcc_by_id(
898 ctrl_state,
899 pcep_pcc_get_pcc_id_by_idx(ctrl_state->pcc, i));
900 }
901 return 0;
902 }
903
904 int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state,
905 struct pce_opts *pce_opts)
906 {
907 assert(ctrl_state != NULL);
908
909 if (pce_opts) {
910 int pcc_id = pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc,
911 pce_opts);
912 if (pcc_id) {
913 pcep_thread_event_remove_pcc_by_id(ctrl_state, pcc_id);
914 } else {
915 return -1;
916 }
917 XFREE(MTYPE_PCEP, pce_opts);
918 } else {
919 pcep_thread_event_remove_pcc_all(ctrl_state);
920 }
921
922 return 0;
923 }
924
925 int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
926 struct path *path)
927 {
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);
932 return 0;
933 }
934
935 int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, int pcc_id)
936 {
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);
940 return 0;
941 }
942
943 int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
944 enum pcep_pathd_event_type type,
945 struct path *path)
946 {
947 int i;
948
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,
953 type, path);
954 }
955 }
956
957 pcep_free_path(path);
958
959 return 0;
960 }
961
962
963 /* ------------ Main Thread Event Handler ------------ */
964
965 int send_to_main(struct ctrl_state *ctrl_state, int pcc_id,
966 enum pcep_main_event_type type, void *payload)
967 {
968 struct pcep_main_event_data *data;
969
970 data = XCALLOC(MTYPE_PCEP, sizeof(*data));
971 data->handler = ctrl_state->main_event_handler;
972 data->type = type;
973 data->pcc_id = pcc_id;
974 data->payload = payload;
975
976 thread_add_event(ctrl_state->main, pcep_main_event_handler,
977 (void *)data, 0, NULL);
978 return 0;
979 }
980
981 int pcep_main_event_handler(struct thread *thread)
982 {
983 /* data unpacking */
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);
991
992 return handler(type, pcc_id, payload);
993 }
994
995
996 /* ------------ Helper functions ------------ */
997
998 void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state)
999 {
1000 assert(fpt != NULL);
1001 fpt->data = ctrl_state;
1002 }
1003
1004 struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt)
1005 {
1006 assert(fpt != NULL);
1007 assert(fpt->data != NULL);
1008
1009 struct ctrl_state *ctrl_state;
1010 ctrl_state = (struct ctrl_state *)fpt->data;
1011 assert(ctrl_state != NULL);
1012 return ctrl_state;
1013 }
1014
1015 int get_next_id(struct ctrl_state *ctrl_state)
1016 {
1017 return ++ctrl_state->pcc_last_id;
1018 }
1019
1020 int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
1021 {
1022 assert(ctrl_state != NULL);
1023 assert(pcep_pcc_get_pcc_id(pcc_state) != 0);
1024
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);
1031 return 0;
1032 } else {
1033 PCEP_DEBUG("Max number of pce ");
1034 return 1;
1035 }
1036 }
1037
1038 void remove_pcc_state(struct ctrl_state *ctrl_state,
1039 struct pcc_state *pcc_state)
1040 {
1041 assert(ctrl_state != NULL);
1042 assert(pcep_pcc_get_pcc_id(pcc_state) != 0);
1043
1044 int idx = 0;
1045 idx = pcep_pcc_get_pcc_idx_by_id(ctrl_state->pcc,
1046 pcep_pcc_get_pcc_id(pcc_state));
1047 if (idx != -1) {
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));
1052 }
1053 }
1054
1055 uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t retry_count)
1056 {
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;
1060 return b;
1061 }
1062
1063 const char *timer_type_name(enum pcep_ctrl_timer_type type)
1064 {
1065 switch (type) {
1066 case TM_UNDEFINED:
1067 return "UNDEFINED";
1068 case TM_RECONNECT_PCC:
1069 return "RECONNECT_PCC";
1070 case TM_PCEPLIB_TIMER:
1071 return "PCEPLIB_TIMER";
1072 case TM_TIMEOUT:
1073 return "TIMEOUT";
1074 default:
1075 return "UNKNOWN";
1076 }
1077 };
1078
1079 const char *timeout_type_name(enum pcep_ctrl_timeout_type type)
1080 {
1081 switch (type) {
1082 case TO_UNDEFINED:
1083 return "UNDEFINED";
1084 case TO_COMPUTATION_REQUEST:
1085 return "COMPUTATION_REQUEST";
1086 default:
1087 return "UNKNOWN";
1088 }
1089 }