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