]>
Commit | Line | Data |
---|---|---|
efba0985 SM |
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" | |
09781197 | 25 | #include "lib/version.h" |
efba0985 SM |
26 | #include "northbound.h" |
27 | #include "frr_pthread.h" | |
28 | #include "jhash.h" | |
6f4196d7 | 29 | #include "network.h" |
efba0985 SM |
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, | |
74971473 JG |
58 | EV_RESET_PCC_SESSION, |
59 | EV_SEND_REPORT, | |
56634922 | 60 | EV_SEND_ERROR, |
74971473 | 61 | EV_PATH_REFINED |
efba0985 SM |
62 | }; |
63 | ||
64 | struct pcep_ctrl_event_data { | |
65 | struct ctrl_state *ctrl_state; | |
66 | enum pcep_ctrl_event_type type; | |
67 | uint32_t sub_type; | |
68 | int pcc_id; | |
69 | void *payload; | |
70 | }; | |
71 | ||
72 | struct pcep_main_event_data { | |
73 | pcep_main_event_handler_t handler; | |
74 | int pcc_id; | |
75 | enum pcep_main_event_type type; | |
76 | void *payload; | |
77 | }; | |
78 | ||
74971473 | 79 | struct pcep_refine_path_event_data { |
efba0985 SM |
80 | struct ctrl_state *ctrl_state; |
81 | int pcc_id; | |
74971473 JG |
82 | pcep_refine_callback_t continue_lsp_update_handler; |
83 | struct path *path; | |
84 | void *payload; | |
efba0985 SM |
85 | }; |
86 | ||
74971473 JG |
87 | /* Synchronous call arguments */ |
88 | ||
89 | struct get_counters_args { | |
efba0985 SM |
90 | struct ctrl_state *ctrl_state; |
91 | int pcc_id; | |
74971473 | 92 | struct counters_group *counters; |
efba0985 SM |
93 | }; |
94 | ||
95 | struct get_pcep_session_args { | |
96 | struct ctrl_state *ctrl_state; | |
97 | int pcc_id; | |
98 | pcep_session *pcep_session; | |
99 | }; | |
100 | ||
101 | /* Internal Functions Called From Main Thread */ | |
102 | static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res); | |
74971473 | 103 | static int pcep_refine_path_event_cb(struct thread *thread); |
efba0985 SM |
104 | |
105 | /* Internal Functions Called From Controller Thread */ | |
106 | static int pcep_thread_finish_event_handler(struct thread *thread); | |
efba0985 SM |
107 | |
108 | /* Controller Thread Timer Handler */ | |
109 | static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, | |
110 | enum pcep_ctrl_timer_type timer_type, | |
111 | enum pcep_ctrl_timeout_type timeout_type, | |
112 | uint32_t delay, void *payload, | |
113 | struct thread **thread); | |
114 | static int schedule_thread_timer_with_cb( | |
115 | struct ctrl_state *ctrl_state, int pcc_id, | |
116 | enum pcep_ctrl_timer_type timer_type, | |
117 | enum pcep_ctrl_timeout_type timeout_type, uint32_t delay, void *payload, | |
118 | struct thread **thread, pcep_ctrl_thread_callback timer_cb); | |
119 | static int pcep_thread_timer_handler(struct thread *thread); | |
120 | ||
121 | /* Controller Thread Socket read/write Handler */ | |
122 | static int schedule_thread_socket(struct ctrl_state *ctrl_state, int pcc_id, | |
123 | enum pcep_ctrl_socket_type type, bool is_read, | |
124 | void *payload, int fd, struct thread **thread, | |
125 | pcep_ctrl_thread_callback cb); | |
126 | ||
127 | /* Controller Thread Event Handler */ | |
128 | static int send_to_thread(struct ctrl_state *ctrl_state, int pcc_id, | |
129 | enum pcep_ctrl_event_type type, uint32_t sub_type, | |
130 | void *payload); | |
131 | static int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id, | |
132 | enum pcep_ctrl_event_type type, | |
133 | uint32_t sub_type, void *payload, | |
134 | pcep_ctrl_thread_callback event_cb); | |
135 | static int pcep_thread_event_handler(struct thread *thread); | |
136 | static int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, | |
137 | struct pcc_opts *opts); | |
138 | static int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, | |
139 | int pcc_id, | |
140 | struct pce_opts *opts); | |
141 | static int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state, | |
142 | int pcc_id); | |
143 | static int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state); | |
144 | static int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, | |
145 | struct pce_opts *pce_opts); | |
146 | static int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, | |
147 | int pcc_id, struct path *path); | |
148 | static int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, | |
149 | int pcc_id); | |
150 | static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state, | |
151 | enum pcep_pathd_event_type type, | |
152 | struct path *path); | |
74971473 JG |
153 | static void |
154 | pcep_thread_path_refined_event(struct ctrl_state *ctrl_state, | |
155 | struct pcep_refine_path_event_data *data); | |
efba0985 SM |
156 | |
157 | /* Main Thread Event Handler */ | |
158 | static int send_to_main(struct ctrl_state *ctrl_state, int pcc_id, | |
159 | enum pcep_main_event_type type, void *payload); | |
160 | static int pcep_main_event_handler(struct thread *thread); | |
161 | ||
162 | /* Helper functions */ | |
163 | static void set_ctrl_state(struct frr_pthread *fpt, | |
164 | struct ctrl_state *ctrl_state); | |
165 | static struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt); | |
166 | int get_next_id(struct ctrl_state *ctrl_state); | |
167 | int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state); | |
168 | void remove_pcc_state(struct ctrl_state *ctrl_state, | |
169 | struct pcc_state *pcc_state); | |
170 | static uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t attempt); | |
171 | static const char *timer_type_name(enum pcep_ctrl_timer_type type); | |
172 | static const char *timeout_type_name(enum pcep_ctrl_timeout_type type); | |
173 | ||
174 | ||
175 | /* ------------ API Functions Called from Main Thread ------------ */ | |
176 | ||
177 | int pcep_ctrl_initialize(struct thread_master *main_thread, | |
178 | struct frr_pthread **fpt, | |
179 | pcep_main_event_handler_t event_handler) | |
180 | { | |
181 | assert(fpt != NULL); | |
182 | ||
183 | int ret = 0; | |
184 | struct ctrl_state *ctrl_state; | |
185 | struct frr_pthread_attr attr = { | |
186 | .start = frr_pthread_attr_default.start, | |
187 | .stop = pcep_ctrl_halt_cb, | |
188 | }; | |
189 | ||
190 | PCEP_DEBUG("Initializing pcep module controller"); | |
191 | ||
192 | /* Create and start the FRR pthread */ | |
5ffdc11e | 193 | *fpt = frr_pthread_new(&attr, "PCEP thread", "pcep_controller"); |
efba0985 SM |
194 | if (*fpt == NULL) { |
195 | flog_err(EC_PATH_SYSTEM_CALL, | |
196 | "failed to initialize PCEP thread"); | |
197 | return 1; | |
198 | } | |
199 | ret = frr_pthread_run(*fpt, NULL); | |
200 | if (ret < 0) { | |
201 | flog_err(EC_PATH_SYSTEM_CALL, "failed to create PCEP thread"); | |
202 | return ret; | |
203 | } | |
204 | frr_pthread_wait_running(*fpt); | |
205 | ||
206 | /* Initialize the thread state */ | |
207 | ctrl_state = XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state)); | |
208 | ctrl_state->main = main_thread; | |
209 | ctrl_state->self = (*fpt)->master; | |
210 | ctrl_state->main_event_handler = event_handler; | |
211 | ctrl_state->pcc_count = 0; | |
212 | ctrl_state->pcc_last_id = 0; | |
213 | ctrl_state->pcc_opts = | |
214 | XCALLOC(MTYPE_PCEP, sizeof(*ctrl_state->pcc_opts)); | |
215 | /* Default to no PCC address defined */ | |
216 | ctrl_state->pcc_opts->addr.ipa_type = IPADDR_NONE; | |
217 | ctrl_state->pcc_opts->port = PCEP_DEFAULT_PORT; | |
218 | ||
219 | /* Keep the state reference for events */ | |
220 | set_ctrl_state(*fpt, ctrl_state); | |
221 | ||
222 | return ret; | |
223 | } | |
224 | ||
225 | int pcep_ctrl_finalize(struct frr_pthread **fpt) | |
226 | { | |
227 | assert(fpt != NULL); | |
228 | ||
229 | int ret = 0; | |
230 | ||
231 | PCEP_DEBUG("Finalizing pcep module controller"); | |
232 | ||
233 | if (*fpt != NULL) { | |
234 | frr_pthread_stop(*fpt, NULL); | |
235 | *fpt = NULL; | |
236 | } | |
237 | ||
238 | return ret; | |
239 | } | |
240 | ||
241 | int pcep_ctrl_update_pcc_options(struct frr_pthread *fpt, struct pcc_opts *opts) | |
242 | { | |
243 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
244 | return send_to_thread(ctrl_state, 0, EV_UPDATE_PCC_OPTS, 0, opts); | |
245 | } | |
246 | ||
247 | int pcep_ctrl_update_pce_options(struct frr_pthread *fpt, struct pce_opts *opts) | |
248 | { | |
249 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
250 | return send_to_thread(ctrl_state, 0, EV_UPDATE_PCE_OPTS, 0, opts); | |
251 | } | |
252 | ||
253 | int pcep_ctrl_remove_pcc(struct frr_pthread *fpt, struct pce_opts *pce_opts) | |
254 | { | |
255 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
256 | return send_to_thread(ctrl_state, 0, EV_REMOVE_PCC, 0, pce_opts); | |
257 | } | |
258 | ||
259 | int pcep_ctrl_reset_pcc_session(struct frr_pthread *fpt, char *pce_name) | |
260 | { | |
261 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
262 | return send_to_thread(ctrl_state, 0, EV_RESET_PCC_SESSION, 0, pce_name); | |
263 | } | |
264 | ||
265 | int pcep_ctrl_pathd_event(struct frr_pthread *fpt, | |
266 | enum pcep_pathd_event_type type, struct path *path) | |
267 | { | |
268 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
269 | return send_to_thread(ctrl_state, 0, EV_PATHD_EVENT, type, path); | |
270 | } | |
271 | ||
272 | int pcep_ctrl_sync_path(struct frr_pthread *fpt, int pcc_id, struct path *path) | |
273 | { | |
274 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
275 | return send_to_thread(ctrl_state, pcc_id, EV_SYNC_PATH, 0, path); | |
276 | } | |
277 | ||
278 | int pcep_ctrl_sync_done(struct frr_pthread *fpt, int pcc_id) | |
279 | { | |
280 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
281 | return send_to_thread(ctrl_state, pcc_id, EV_SYNC_DONE, 0, NULL); | |
282 | } | |
283 | ||
284 | struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt, | |
285 | int pcc_id) | |
286 | { | |
287 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
74971473 JG |
288 | struct counters_group *counters = NULL; |
289 | struct pcc_state *pcc_state; | |
290 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
291 | if (pcc_state) { | |
292 | counters = pcep_lib_copy_counters(pcc_state->sess); | |
293 | } | |
294 | return counters; | |
efba0985 SM |
295 | } |
296 | ||
297 | pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id) | |
298 | { | |
299 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
74971473 JG |
300 | struct pcc_state *pcc_state; |
301 | pcep_session *session = NULL; | |
302 | ||
303 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
304 | if (pcc_state) { | |
305 | session = pcep_lib_copy_pcep_session(pcc_state->sess); | |
306 | } | |
307 | return session; | |
efba0985 SM |
308 | } |
309 | ||
310 | struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt, | |
311 | const char *pce_name) | |
312 | { | |
313 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
74971473 JG |
314 | struct pcep_pcc_info *pcc_info = XCALLOC(MTYPE_PCEP, sizeof(*pcc_info)); |
315 | if( pcc_info && ctrl_state){ | |
316 | strlcpy(pcc_info->pce_name, pce_name, sizeof(pcc_info->pce_name)); | |
317 | pcep_pcc_copy_pcc_info(ctrl_state->pcc, pcc_info); | |
318 | } | |
efba0985 | 319 | |
74971473 | 320 | return pcc_info; |
efba0985 SM |
321 | } |
322 | ||
74971473 JG |
323 | int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id, |
324 | struct path *path, bool is_stable) | |
efba0985 | 325 | { |
efba0985 | 326 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); |
74971473 JG |
327 | return send_to_thread(ctrl_state, pcc_id, EV_SEND_REPORT, is_stable, |
328 | path); | |
efba0985 SM |
329 | } |
330 | ||
74971473 | 331 | |
56634922 JG |
332 | int pcep_ctrl_send_error(struct frr_pthread *fpt, int pcc_id, |
333 | struct pcep_error *error) | |
334 | { | |
335 | struct ctrl_state *ctrl_state = get_ctrl_state(fpt); | |
336 | return send_to_thread(ctrl_state, pcc_id, EV_SEND_ERROR, 0, error); | |
337 | } | |
338 | ||
339 | ||
efba0985 SM |
340 | /* ------------ Internal Functions Called from Main Thread ------------ */ |
341 | ||
342 | int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res) | |
343 | { | |
344 | thread_add_event(fpt->master, pcep_thread_finish_event_handler, | |
345 | (void *)fpt, 0, NULL); | |
346 | pthread_join(fpt->thread, res); | |
347 | ||
348 | return 0; | |
349 | } | |
350 | ||
74971473 JG |
351 | int pcep_refine_path_event_cb(struct thread *thread) |
352 | { | |
353 | struct pcep_refine_path_event_data *data = THREAD_ARG(thread); | |
354 | assert(data != NULL); | |
355 | struct ctrl_state *ctrl_state = data->ctrl_state; | |
356 | struct path *path = data->path; | |
357 | assert(path != NULL); | |
358 | int pcc_id = data->pcc_id; | |
359 | ||
360 | ||
361 | path_pcep_refine_path(path); | |
362 | return send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data); | |
363 | } | |
364 | ||
efba0985 SM |
365 | |
366 | /* ------------ API Functions Called From Controller Thread ------------ */ | |
367 | ||
368 | void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id) | |
369 | { | |
370 | send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_START_SYNC, NULL); | |
371 | } | |
372 | ||
373 | void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id, | |
374 | struct path *path) | |
375 | { | |
376 | send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_UPDATE_CANDIDATE, | |
377 | path); | |
378 | } | |
379 | ||
56634922 JG |
380 | void pcep_thread_initiate_path(struct ctrl_state *ctrl_state, int pcc_id, |
381 | struct path *path) | |
382 | { | |
383 | send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_INITIATE_CANDIDATE, | |
384 | path); | |
385 | } | |
386 | ||
efba0985 SM |
387 | void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state, |
388 | struct pcc_state *pcc_state) | |
389 | { | |
390 | if (!pcc_state) | |
391 | return; | |
392 | /* Will be deleted when the event is handled */ | |
393 | char *originator = XSTRDUP(MTYPE_PCEP, pcc_state->originator); | |
394 | PCEP_DEBUG("schedule candidate path segments removal for originator %s", | |
395 | originator); | |
396 | send_to_main(ctrl_state, pcep_pcc_get_pcc_id(pcc_state), | |
397 | PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP, originator); | |
398 | } | |
399 | ||
400 | void pcep_thread_schedule_sync_best_pce(struct ctrl_state *ctrl_state, | |
401 | int pcc_id, int delay, | |
402 | struct thread **thread) | |
403 | { | |
404 | ||
405 | schedule_thread_timer(ctrl_state, pcc_id, TM_CALCULATE_BEST_PCE, | |
406 | TO_UNDEFINED, delay, NULL, thread); | |
407 | } | |
408 | ||
409 | void pcep_thread_cancel_timer(struct thread **thread) | |
410 | { | |
411 | if (thread == NULL || *thread == NULL) { | |
412 | return; | |
413 | } | |
414 | ||
415 | struct pcep_ctrl_timer_data *data = THREAD_ARG(*thread); | |
416 | PCEP_DEBUG("Timer %s / %s canceled", timer_type_name(data->timer_type), | |
417 | timeout_type_name(data->timeout_type)); | |
418 | if (data != NULL) { | |
419 | XFREE(MTYPE_PCEP, data); | |
420 | } | |
421 | ||
422 | if ((*thread)->master->owner == pthread_self()) { | |
423 | thread_cancel(thread); | |
424 | } else { | |
425 | thread_cancel_async((*thread)->master, thread, NULL); | |
426 | } | |
427 | } | |
428 | ||
429 | void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id, | |
430 | int retry_count, struct thread **thread) | |
431 | { | |
432 | uint32_t delay = backoff_delay(MAX_RECONNECT_DELAY, 1, retry_count); | |
433 | PCEP_DEBUG("Schedule RECONNECT_PCC for %us (retry %u)", delay, | |
434 | retry_count); | |
435 | schedule_thread_timer(ctrl_state, pcc_id, TM_RECONNECT_PCC, | |
436 | TO_UNDEFINED, delay, NULL, thread); | |
437 | } | |
438 | ||
439 | void pcep_thread_schedule_timeout(struct ctrl_state *ctrl_state, int pcc_id, | |
440 | enum pcep_ctrl_timeout_type timeout_type, | |
441 | uint32_t delay, void *param, | |
442 | struct thread **thread) | |
443 | { | |
444 | assert(timeout_type > TO_UNDEFINED); | |
445 | assert(timeout_type < TO_MAX); | |
446 | PCEP_DEBUG("Schedule timeout %s for %us", | |
447 | timeout_type_name(timeout_type), delay); | |
448 | schedule_thread_timer(ctrl_state, pcc_id, TM_TIMEOUT, timeout_type, | |
449 | delay, param, thread); | |
450 | } | |
451 | ||
452 | void pcep_thread_schedule_pceplib_timer(struct ctrl_state *ctrl_state, | |
453 | int delay, void *payload, | |
454 | struct thread **thread, | |
455 | pcep_ctrl_thread_callback timer_cb) | |
456 | { | |
457 | PCEP_DEBUG("Schedule PCEPLIB_TIMER for %us", delay); | |
458 | schedule_thread_timer_with_cb(ctrl_state, 0, TM_PCEPLIB_TIMER, | |
459 | TO_UNDEFINED, delay, payload, thread, | |
460 | timer_cb); | |
461 | } | |
462 | ||
463 | void pcep_thread_schedule_session_timeout(struct ctrl_state *ctrl_state, | |
464 | int pcc_id, int delay, | |
465 | struct thread **thread) | |
466 | { | |
467 | PCEP_DEBUG("Schedule session_timeout interval for %us", delay); | |
468 | schedule_thread_timer(ctrl_state, pcc_id, TM_SESSION_TIMEOUT_PCC, | |
469 | TO_UNDEFINED, delay, NULL, thread); | |
470 | } | |
471 | ||
472 | int pcep_thread_pcc_count(struct ctrl_state *ctrl_state) | |
473 | { | |
474 | if (ctrl_state == NULL) { | |
475 | return 0; | |
476 | } | |
477 | ||
478 | return ctrl_state->pcc_count; | |
479 | } | |
480 | ||
74971473 JG |
481 | int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id, |
482 | pcep_refine_callback_t cb, struct path *path, | |
483 | void *payload) | |
484 | { | |
485 | struct pcep_refine_path_event_data *data; | |
486 | ||
487 | data = XCALLOC(MTYPE_PCEP, sizeof(*data)); | |
488 | data->ctrl_state = ctrl_state; | |
489 | data->path = path; | |
490 | data->pcc_id = pcc_id; | |
491 | data->continue_lsp_update_handler = cb; | |
492 | data->payload = payload; | |
493 | ||
494 | thread_add_event(ctrl_state->main, pcep_refine_path_event_cb, | |
495 | (void *)data, 0, NULL); | |
496 | return 0; | |
497 | } | |
498 | ||
499 | void pcep_thread_path_refined_event(struct ctrl_state *ctrl_state, | |
500 | struct pcep_refine_path_event_data *data) | |
501 | { | |
502 | assert(data != NULL); | |
503 | int pcc_id = data->pcc_id; | |
504 | pcep_refine_callback_t continue_lsp_update_handler = data->continue_lsp_update_handler; | |
505 | assert(continue_lsp_update_handler != NULL); | |
506 | struct path *path = data->path; | |
507 | void *payload = data->payload; | |
508 | struct pcc_state *pcc_state = NULL; | |
509 | XFREE(MTYPE_PCEP, data); | |
510 | ||
511 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
512 | continue_lsp_update_handler(ctrl_state, pcc_state, path, payload); | |
513 | } | |
514 | ||
515 | ||
efba0985 SM |
516 | /* ------------ Internal Functions Called From Controller Thread ------------ */ |
517 | ||
518 | int pcep_thread_finish_event_handler(struct thread *thread) | |
519 | { | |
520 | int i; | |
521 | struct frr_pthread *fpt = THREAD_ARG(thread); | |
522 | struct ctrl_state *ctrl_state = fpt->data; | |
523 | ||
524 | assert(ctrl_state != NULL); | |
525 | ||
526 | for (i = 0; i < MAX_PCC; i++) { | |
527 | if (ctrl_state->pcc[i]) { | |
528 | pcep_pcc_finalize(ctrl_state, ctrl_state->pcc[i]); | |
529 | ctrl_state->pcc[i] = NULL; | |
530 | } | |
531 | } | |
532 | ||
533 | XFREE(MTYPE_PCEP, ctrl_state->pcc_opts); | |
534 | XFREE(MTYPE_PCEP, ctrl_state); | |
535 | fpt->data = NULL; | |
536 | ||
537 | atomic_store_explicit(&fpt->running, false, memory_order_relaxed); | |
538 | return 0; | |
539 | } | |
540 | ||
efba0985 SM |
541 | /* ------------ Controller Thread Timer Handler ------------ */ |
542 | ||
543 | int schedule_thread_timer_with_cb(struct ctrl_state *ctrl_state, int pcc_id, | |
544 | enum pcep_ctrl_timer_type timer_type, | |
545 | enum pcep_ctrl_timeout_type timeout_type, | |
546 | uint32_t delay, void *payload, | |
547 | struct thread **thread, | |
548 | pcep_ctrl_thread_callback timer_cb) | |
549 | { | |
550 | assert(thread != NULL); | |
551 | ||
552 | struct pcep_ctrl_timer_data *data; | |
553 | ||
554 | data = XCALLOC(MTYPE_PCEP, sizeof(*data)); | |
555 | data->ctrl_state = ctrl_state; | |
556 | data->timer_type = timer_type; | |
557 | data->timeout_type = timeout_type; | |
558 | data->pcc_id = pcc_id; | |
559 | data->payload = payload; | |
560 | ||
561 | thread_add_timer(ctrl_state->self, timer_cb, (void *)data, delay, | |
562 | thread); | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
567 | int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id, | |
568 | enum pcep_ctrl_timer_type timer_type, | |
569 | enum pcep_ctrl_timeout_type timeout_type, | |
570 | uint32_t delay, void *payload, struct thread **thread) | |
571 | { | |
572 | return schedule_thread_timer_with_cb(ctrl_state, pcc_id, timer_type, | |
573 | timeout_type, delay, payload, | |
574 | thread, pcep_thread_timer_handler); | |
575 | } | |
576 | ||
577 | int pcep_thread_timer_handler(struct thread *thread) | |
578 | { | |
579 | /* data unpacking */ | |
580 | struct pcep_ctrl_timer_data *data = THREAD_ARG(thread); | |
581 | assert(data != NULL); | |
582 | struct ctrl_state *ctrl_state = data->ctrl_state; | |
583 | assert(ctrl_state != NULL); | |
584 | enum pcep_ctrl_timer_type timer_type = data->timer_type; | |
585 | enum pcep_ctrl_timeout_type timeout_type = data->timeout_type; | |
586 | int pcc_id = data->pcc_id; | |
587 | void *param = data->payload; | |
588 | XFREE(MTYPE_PCEP, data); | |
589 | ||
590 | int ret = 0; | |
591 | struct pcc_state *pcc_state = NULL; | |
592 | ||
593 | switch (timer_type) { | |
594 | case TM_RECONNECT_PCC: | |
595 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
596 | if (!pcc_state) | |
597 | return ret; | |
598 | pcep_pcc_reconnect(ctrl_state, pcc_state); | |
599 | break; | |
600 | case TM_TIMEOUT: | |
601 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
602 | if (!pcc_state) | |
603 | return ret; | |
604 | pcep_pcc_timeout_handler(ctrl_state, pcc_state, timeout_type, | |
605 | param); | |
606 | break; | |
607 | case TM_CALCULATE_BEST_PCE: | |
608 | /* Previous best disconnect so new best should be synced */ | |
609 | ret = pcep_pcc_timer_update_best_pce(ctrl_state, pcc_id); | |
610 | break; | |
611 | case TM_SESSION_TIMEOUT_PCC: | |
612 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
613 | pcep_thread_remove_candidate_path_segments(ctrl_state, | |
614 | pcc_state); | |
615 | break; | |
616 | default: | |
617 | flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, | |
618 | "Unknown controller timer triggered: %u", timer_type); | |
619 | break; | |
620 | } | |
621 | ||
622 | return ret; | |
623 | } | |
624 | ||
625 | int pcep_thread_pcep_event(struct thread *thread) | |
626 | { | |
627 | struct pcep_ctrl_event_data *data = THREAD_ARG(thread); | |
628 | assert(data != NULL); | |
629 | struct ctrl_state *ctrl_state = data->ctrl_state; | |
630 | pcep_event *event = data->payload; | |
631 | XFREE(MTYPE_PCEP, data); | |
632 | int i; | |
633 | ||
634 | for (i = 0; i < MAX_PCC; i++) { | |
635 | if (ctrl_state->pcc[i]) { | |
636 | struct pcc_state *pcc_state = ctrl_state->pcc[i]; | |
637 | if (pcc_state->sess != event->session) | |
638 | continue; | |
639 | pcep_pcc_pcep_event_handler(ctrl_state, pcc_state, | |
640 | event); | |
641 | break; | |
642 | } | |
643 | } | |
644 | destroy_pcep_event(event); | |
645 | ||
646 | return 0; | |
647 | } | |
648 | ||
649 | /* ------------ Controller Thread Socket Functions ------------ */ | |
650 | ||
651 | int schedule_thread_socket(struct ctrl_state *ctrl_state, int pcc_id, | |
652 | enum pcep_ctrl_socket_type type, bool is_read, | |
653 | void *payload, int fd, struct thread **thread, | |
654 | pcep_ctrl_thread_callback socket_cb) | |
655 | { | |
656 | assert(thread != NULL); | |
657 | ||
658 | struct pcep_ctrl_socket_data *data; | |
659 | ||
660 | data = XCALLOC(MTYPE_PCEP, sizeof(*data)); | |
661 | data->ctrl_state = ctrl_state; | |
662 | data->type = type; | |
663 | data->is_read = is_read; | |
664 | data->fd = fd; | |
665 | data->pcc_id = pcc_id; | |
666 | data->payload = payload; | |
667 | ||
668 | if (is_read) { | |
669 | thread_add_read(ctrl_state->self, socket_cb, (void *)data, fd, | |
670 | thread); | |
671 | } else { | |
672 | thread_add_write(ctrl_state->self, socket_cb, (void *)data, fd, | |
673 | thread); | |
674 | } | |
675 | ||
676 | return 0; | |
677 | } | |
678 | ||
679 | int pcep_thread_socket_write(void *fpt, void **thread, int fd, void *payload, | |
680 | pcep_ctrl_thread_callback socket_cb) | |
681 | { | |
682 | struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data; | |
683 | ||
684 | return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, false, | |
685 | payload, fd, (struct thread **)thread, | |
686 | socket_cb); | |
687 | } | |
688 | ||
689 | int pcep_thread_socket_read(void *fpt, void **thread, int fd, void *payload, | |
690 | pcep_ctrl_thread_callback socket_cb) | |
691 | { | |
692 | struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data; | |
693 | ||
694 | return schedule_thread_socket(ctrl_state, 0, SOCK_PCEPLIB, true, | |
695 | payload, fd, (struct thread **)thread, | |
696 | socket_cb); | |
697 | } | |
698 | ||
699 | int pcep_thread_send_ctrl_event(void *fpt, void *payload, | |
700 | pcep_ctrl_thread_callback cb) | |
701 | { | |
702 | struct ctrl_state *ctrl_state = ((struct frr_pthread *)fpt)->data; | |
703 | ||
704 | return send_to_thread_with_cb(ctrl_state, 0, EV_PCEPLIB_EVENT, 0, | |
705 | payload, cb); | |
706 | } | |
707 | ||
708 | /* ------------ Controller Thread Event Handler ------------ */ | |
709 | ||
710 | int send_to_thread(struct ctrl_state *ctrl_state, int pcc_id, | |
711 | enum pcep_ctrl_event_type type, uint32_t sub_type, | |
712 | void *payload) | |
713 | { | |
714 | return send_to_thread_with_cb(ctrl_state, pcc_id, type, sub_type, | |
715 | payload, pcep_thread_event_handler); | |
716 | } | |
717 | ||
718 | int send_to_thread_with_cb(struct ctrl_state *ctrl_state, int pcc_id, | |
719 | enum pcep_ctrl_event_type type, uint32_t sub_type, | |
720 | void *payload, pcep_ctrl_thread_callback event_cb) | |
721 | { | |
722 | struct pcep_ctrl_event_data *data; | |
723 | ||
724 | data = XCALLOC(MTYPE_PCEP, sizeof(*data)); | |
725 | data->ctrl_state = ctrl_state; | |
726 | data->type = type; | |
727 | data->sub_type = sub_type; | |
728 | data->pcc_id = pcc_id; | |
729 | data->payload = payload; | |
730 | ||
731 | thread_add_event(ctrl_state->self, event_cb, (void *)data, 0, NULL); | |
732 | ||
733 | return 0; | |
734 | } | |
735 | ||
736 | int pcep_thread_event_handler(struct thread *thread) | |
737 | { | |
738 | /* data unpacking */ | |
739 | struct pcep_ctrl_event_data *data = THREAD_ARG(thread); | |
740 | assert(data != NULL); | |
741 | struct ctrl_state *ctrl_state = data->ctrl_state; | |
742 | assert(ctrl_state != NULL); | |
743 | enum pcep_ctrl_event_type type = data->type; | |
744 | uint32_t sub_type = data->sub_type; | |
745 | int pcc_id = data->pcc_id; | |
746 | void *payload = data->payload; | |
747 | XFREE(MTYPE_PCEP, data); | |
748 | ||
749 | int ret = 0; | |
750 | ||
751 | /* Possible sub-type values */ | |
752 | enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED; | |
753 | ||
74971473 | 754 | /* Possible payload values, maybe an union would be better... */ |
efba0985 SM |
755 | struct path *path = NULL; |
756 | struct pcc_opts *pcc_opts = NULL; | |
757 | struct pce_opts *pce_opts = NULL; | |
758 | struct pcc_state *pcc_state = NULL; | |
74971473 JG |
759 | struct pcep_refine_path_event_data *refine_data = NULL; |
760 | ||
761 | struct path *path_copy = NULL; | |
56634922 | 762 | struct pcep_error *error = NULL; |
efba0985 SM |
763 | |
764 | switch (type) { | |
765 | case EV_UPDATE_PCC_OPTS: | |
766 | assert(payload != NULL); | |
767 | pcc_opts = (struct pcc_opts *)payload; | |
768 | ret = pcep_thread_event_update_pcc_options(ctrl_state, | |
769 | pcc_opts); | |
770 | break; | |
771 | case EV_UPDATE_PCE_OPTS: | |
772 | assert(payload != NULL); | |
773 | pce_opts = (struct pce_opts *)payload; | |
774 | ret = pcep_thread_event_update_pce_options(ctrl_state, pcc_id, | |
775 | pce_opts); | |
776 | break; | |
777 | case EV_REMOVE_PCC: | |
778 | pce_opts = (struct pce_opts *)payload; | |
779 | ret = pcep_thread_event_remove_pcc(ctrl_state, pce_opts); | |
780 | if (ret == 0) { | |
781 | ret = pcep_pcc_multi_pce_remove_pcc(ctrl_state, | |
782 | ctrl_state->pcc); | |
783 | } | |
784 | break; | |
785 | case EV_PATHD_EVENT: | |
786 | assert(payload != NULL); | |
787 | path_event_type = (enum pcep_pathd_event_type)sub_type; | |
788 | path = (struct path *)payload; | |
789 | ret = pcep_thread_event_pathd_event(ctrl_state, path_event_type, | |
790 | path); | |
791 | break; | |
792 | case EV_SYNC_PATH: | |
793 | assert(payload != NULL); | |
794 | path = (struct path *)payload; | |
795 | pcep_pcc_multi_pce_sync_path(ctrl_state, pcc_id, | |
796 | ctrl_state->pcc); | |
797 | pcep_thread_event_sync_path(ctrl_state, pcc_id, path); | |
798 | break; | |
799 | case EV_SYNC_DONE: | |
800 | ret = pcep_thread_event_sync_done(ctrl_state, pcc_id); | |
801 | break; | |
802 | case EV_RESET_PCC_SESSION: | |
803 | pcc_state = pcep_pcc_get_pcc_by_name(ctrl_state->pcc, | |
804 | (const char *)payload); | |
805 | if (pcc_state) { | |
806 | pcep_pcc_disable(ctrl_state, pcc_state); | |
807 | ret = pcep_pcc_enable(ctrl_state, pcc_state); | |
808 | } else { | |
809 | flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, | |
810 | "Cannot reset state for PCE: %s", | |
811 | (const char *)payload); | |
812 | } | |
813 | break; | |
74971473 JG |
814 | case EV_SEND_REPORT: |
815 | assert(payload != NULL); | |
816 | path = (struct path *)payload; | |
817 | if (pcc_id == 0) { | |
818 | for (int i = 0; i < MAX_PCC; i++) { | |
819 | if (ctrl_state->pcc[i]) { | |
820 | path_copy = pcep_copy_path(path); | |
821 | pcep_pcc_send_report( | |
822 | ctrl_state, ctrl_state->pcc[i], | |
823 | path_copy, (bool)sub_type); | |
824 | } | |
825 | } | |
826 | } else { | |
827 | pcc_state = | |
828 | pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
829 | pcep_pcc_send_report(ctrl_state, pcc_state, path, | |
830 | (bool)sub_type); | |
831 | } | |
832 | break; | |
833 | case EV_PATH_REFINED: | |
834 | assert(payload != NULL); | |
835 | refine_data = (struct pcep_refine_path_event_data *)payload; | |
836 | pcep_thread_path_refined_event(ctrl_state, refine_data); | |
837 | break; | |
56634922 JG |
838 | case EV_SEND_ERROR: |
839 | assert(payload != NULL); | |
840 | error = (struct pcep_error *)payload; | |
841 | pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
842 | pcep_pcc_send_error(ctrl_state, pcc_state, error, | |
843 | (bool)sub_type); | |
844 | break; | |
efba0985 SM |
845 | default: |
846 | flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR, | |
847 | "Unexpected event received in controller thread: %u", | |
848 | type); | |
849 | break; | |
850 | } | |
851 | ||
852 | return ret; | |
853 | } | |
854 | ||
855 | int pcep_thread_event_update_pcc_options(struct ctrl_state *ctrl_state, | |
856 | struct pcc_opts *opts) | |
857 | { | |
858 | assert(opts != NULL); | |
859 | if (ctrl_state->pcc_opts != NULL) { | |
860 | XFREE(MTYPE_PCEP, ctrl_state->pcc_opts); | |
861 | } | |
862 | ctrl_state->pcc_opts = opts; | |
863 | return 0; | |
864 | } | |
865 | ||
866 | int pcep_thread_event_update_pce_options(struct ctrl_state *ctrl_state, | |
867 | int pcc_id, struct pce_opts *pce_opts) | |
868 | { | |
869 | if (!pce_opts || !ctrl_state) { | |
870 | return 0; | |
871 | } | |
872 | struct pcc_state *pcc_state; | |
873 | struct pcc_opts *pcc_opts; | |
874 | ||
875 | int current_pcc_id = | |
876 | pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, pce_opts); | |
877 | if (current_pcc_id) { | |
878 | pcc_state = | |
879 | pcep_pcc_get_pcc_by_id(ctrl_state->pcc, current_pcc_id); | |
880 | } else { | |
881 | pcc_state = pcep_pcc_initialize(ctrl_state, | |
882 | get_next_id(ctrl_state)); | |
883 | if (set_pcc_state(ctrl_state, pcc_state)) { | |
884 | XFREE(MTYPE_PCEP, pcc_state); | |
885 | return 0; | |
886 | } | |
887 | } | |
888 | ||
889 | /* Copy the pcc options to delegate it to the update function */ | |
890 | pcc_opts = XCALLOC(MTYPE_PCEP, sizeof(*pcc_opts)); | |
891 | memcpy(pcc_opts, ctrl_state->pcc_opts, sizeof(*pcc_opts)); | |
892 | ||
893 | if (pcep_pcc_update(ctrl_state, pcc_state, pcc_opts, pce_opts)) { | |
894 | flog_err(EC_PATH_PCEP_PCC_CONF_UPDATE, | |
895 | "failed to update PCC configuration"); | |
896 | } | |
897 | ||
898 | ||
899 | return 0; | |
900 | } | |
901 | ||
902 | int pcep_thread_event_remove_pcc_by_id(struct ctrl_state *ctrl_state, | |
903 | int pcc_id) | |
904 | { | |
905 | if (pcc_id) { | |
906 | struct pcc_state *pcc_state = | |
907 | pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
908 | if (pcc_state) { | |
909 | remove_pcc_state(ctrl_state, pcc_state); | |
910 | pcep_pcc_finalize(ctrl_state, pcc_state); | |
911 | } | |
912 | } | |
913 | return 0; | |
914 | } | |
915 | ||
916 | int pcep_thread_event_remove_pcc_all(struct ctrl_state *ctrl_state) | |
917 | { | |
918 | assert(ctrl_state != NULL); | |
919 | ||
920 | for (int i = 0; i < MAX_PCC; i++) { | |
921 | pcep_thread_event_remove_pcc_by_id( | |
922 | ctrl_state, | |
923 | pcep_pcc_get_pcc_id_by_idx(ctrl_state->pcc, i)); | |
924 | } | |
925 | return 0; | |
926 | } | |
927 | ||
928 | int pcep_thread_event_remove_pcc(struct ctrl_state *ctrl_state, | |
929 | struct pce_opts *pce_opts) | |
930 | { | |
931 | assert(ctrl_state != NULL); | |
932 | ||
933 | if (pce_opts) { | |
934 | int pcc_id = pcep_pcc_get_pcc_id_by_ip_port(ctrl_state->pcc, | |
935 | pce_opts); | |
936 | if (pcc_id) { | |
937 | pcep_thread_event_remove_pcc_by_id(ctrl_state, pcc_id); | |
938 | } else { | |
939 | return -1; | |
940 | } | |
941 | XFREE(MTYPE_PCEP, pce_opts); | |
942 | } else { | |
943 | pcep_thread_event_remove_pcc_all(ctrl_state); | |
944 | } | |
945 | ||
946 | return 0; | |
947 | } | |
948 | ||
949 | int pcep_thread_event_sync_path(struct ctrl_state *ctrl_state, int pcc_id, | |
950 | struct path *path) | |
951 | { | |
952 | struct pcc_state *pcc_state = | |
953 | pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
954 | pcep_pcc_sync_path(ctrl_state, pcc_state, path); | |
955 | pcep_free_path(path); | |
956 | return 0; | |
957 | } | |
958 | ||
959 | int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state, int pcc_id) | |
960 | { | |
961 | struct pcc_state *pcc_state = | |
962 | pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id); | |
963 | pcep_pcc_sync_done(ctrl_state, pcc_state); | |
964 | return 0; | |
965 | } | |
966 | ||
967 | int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state, | |
968 | enum pcep_pathd_event_type type, | |
969 | struct path *path) | |
970 | { | |
971 | int i; | |
972 | ||
973 | for (i = 0; i < MAX_PCC; i++) { | |
974 | if (ctrl_state->pcc[i]) { | |
975 | struct pcc_state *pcc_state = ctrl_state->pcc[i]; | |
976 | pcep_pcc_pathd_event_handler(ctrl_state, pcc_state, | |
977 | type, path); | |
978 | } | |
979 | } | |
980 | ||
981 | pcep_free_path(path); | |
982 | ||
983 | return 0; | |
984 | } | |
985 | ||
986 | ||
987 | /* ------------ Main Thread Event Handler ------------ */ | |
988 | ||
989 | int send_to_main(struct ctrl_state *ctrl_state, int pcc_id, | |
990 | enum pcep_main_event_type type, void *payload) | |
991 | { | |
992 | struct pcep_main_event_data *data; | |
993 | ||
994 | data = XCALLOC(MTYPE_PCEP, sizeof(*data)); | |
995 | data->handler = ctrl_state->main_event_handler; | |
996 | data->type = type; | |
997 | data->pcc_id = pcc_id; | |
998 | data->payload = payload; | |
999 | ||
1000 | thread_add_event(ctrl_state->main, pcep_main_event_handler, | |
1001 | (void *)data, 0, NULL); | |
1002 | return 0; | |
1003 | } | |
1004 | ||
1005 | int pcep_main_event_handler(struct thread *thread) | |
1006 | { | |
1007 | /* data unpacking */ | |
1008 | struct pcep_main_event_data *data = THREAD_ARG(thread); | |
1009 | assert(data != NULL); | |
1010 | pcep_main_event_handler_t handler = data->handler; | |
1011 | enum pcep_main_event_type type = data->type; | |
1012 | int pcc_id = data->pcc_id; | |
1013 | void *payload = data->payload; | |
1014 | XFREE(MTYPE_PCEP, data); | |
1015 | ||
1016 | return handler(type, pcc_id, payload); | |
1017 | } | |
1018 | ||
1019 | ||
1020 | /* ------------ Helper functions ------------ */ | |
74971473 | 1021 | |
efba0985 SM |
1022 | void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state) |
1023 | { | |
1024 | assert(fpt != NULL); | |
1025 | fpt->data = ctrl_state; | |
1026 | } | |
1027 | ||
1028 | struct ctrl_state *get_ctrl_state(struct frr_pthread *fpt) | |
1029 | { | |
1030 | assert(fpt != NULL); | |
1031 | assert(fpt->data != NULL); | |
1032 | ||
1033 | struct ctrl_state *ctrl_state; | |
1034 | ctrl_state = (struct ctrl_state *)fpt->data; | |
1035 | assert(ctrl_state != NULL); | |
1036 | return ctrl_state; | |
1037 | } | |
1038 | ||
1039 | int get_next_id(struct ctrl_state *ctrl_state) | |
1040 | { | |
1041 | return ++ctrl_state->pcc_last_id; | |
1042 | } | |
1043 | ||
1044 | int set_pcc_state(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state) | |
1045 | { | |
1046 | assert(ctrl_state != NULL); | |
1047 | assert(pcep_pcc_get_pcc_id(pcc_state) != 0); | |
1048 | ||
1049 | int current_pcc_idx = pcep_pcc_get_free_pcc_idx(ctrl_state->pcc); | |
1050 | if (current_pcc_idx >= 0) { | |
1051 | ctrl_state->pcc[current_pcc_idx] = pcc_state; | |
1052 | ctrl_state->pcc_count++; | |
1053 | PCEP_DEBUG("added pce pcc_id (%d) idx (%d)", | |
1054 | pcep_pcc_get_pcc_id(pcc_state), current_pcc_idx); | |
1055 | return 0; | |
1056 | } else { | |
1057 | PCEP_DEBUG("Max number of pce "); | |
1058 | return 1; | |
1059 | } | |
1060 | } | |
1061 | ||
1062 | void remove_pcc_state(struct ctrl_state *ctrl_state, | |
1063 | struct pcc_state *pcc_state) | |
1064 | { | |
1065 | assert(ctrl_state != NULL); | |
1066 | assert(pcep_pcc_get_pcc_id(pcc_state) != 0); | |
1067 | ||
1068 | int idx = 0; | |
1069 | idx = pcep_pcc_get_pcc_idx_by_id(ctrl_state->pcc, | |
1070 | pcep_pcc_get_pcc_id(pcc_state)); | |
1071 | if (idx != -1) { | |
1072 | ctrl_state->pcc[idx] = NULL; | |
1073 | ctrl_state->pcc_count--; | |
1074 | PCEP_DEBUG("removed pce pcc_id (%d)", | |
1075 | pcep_pcc_get_pcc_id(pcc_state)); | |
1076 | } | |
1077 | } | |
1078 | ||
1079 | uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t retry_count) | |
1080 | { | |
1081 | uint32_t a = min(max, base * (1 << retry_count)); | |
6f4196d7 | 1082 | uint64_t r = frr_weak_random(), m = RAND_MAX; |
efba0985 SM |
1083 | uint32_t b = (a / 2) + (r * (a / 2)) / m; |
1084 | return b; | |
1085 | } | |
1086 | ||
1087 | const char *timer_type_name(enum pcep_ctrl_timer_type type) | |
1088 | { | |
1089 | switch (type) { | |
1090 | case TM_UNDEFINED: | |
1091 | return "UNDEFINED"; | |
1092 | case TM_RECONNECT_PCC: | |
1093 | return "RECONNECT_PCC"; | |
1094 | case TM_PCEPLIB_TIMER: | |
1095 | return "PCEPLIB_TIMER"; | |
1096 | case TM_TIMEOUT: | |
1097 | return "TIMEOUT"; | |
1098 | default: | |
1099 | return "UNKNOWN"; | |
1100 | } | |
1101 | }; | |
1102 | ||
1103 | const char *timeout_type_name(enum pcep_ctrl_timeout_type type) | |
1104 | { | |
1105 | switch (type) { | |
1106 | case TO_UNDEFINED: | |
1107 | return "UNDEFINED"; | |
1108 | case TO_COMPUTATION_REQUEST: | |
1109 | return "COMPUTATION_REQUEST"; | |
1110 | default: | |
1111 | return "UNKNOWN"; | |
1112 | } | |
1113 | } |