1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 NetDEF, Inc.
7 #include "pceplib/pcep_utils_counters.h"
14 #include "lib/version.h"
15 #include "northbound.h"
16 #include "frr_pthread.h"
18 #include "termtable.h"
20 #include "pathd/pathd.h"
21 #include "pathd/path_errors.h"
22 #include "pathd/path_pcep.h"
23 #include "pathd/path_pcep_cli.h"
24 #include "pathd/path_pcep_controller.h"
25 #include "pathd/path_pcep_lib.h"
26 #include "pathd/path_pcep_config.h"
27 #include "pathd/path_pcep_debug.h"
29 DEFINE_MTYPE(PATHD
, PCEP
, "PCEP module");
34 static struct pcep_glob pcep_glob_space
= {.dbg
= {0, "pathd module: pcep"}};
35 struct pcep_glob
*pcep_g
= &pcep_glob_space
;
37 /* Main Thread Even Handler */
38 static int pcep_main_event_handler(enum pcep_main_event_type type
, int pcc_id
,
40 static int pcep_main_event_start_sync(int pcc_id
);
41 static int pcep_main_event_start_sync_cb(struct path
*path
, void *arg
);
42 static int pcep_main_event_initiate_candidate(struct path
*path
);
43 static int pcep_main_event_update_candidate(struct path
*path
);
44 static int pcep_main_event_remove_candidate_segments(const char *originator
,
47 /* Hook Handlers called from the Main Thread */
48 static int pathd_candidate_created_handler(struct srte_candidate
*candidate
);
49 static int pathd_candidate_updated_handler(struct srte_candidate
*candidate
);
50 static int pathd_candidate_removed_handler(struct srte_candidate
*candidate
);
52 /* Path manipulation functions */
53 static struct path_metric
*pcep_copy_metrics(struct path_metric
*metric
);
54 static struct path_hop
*pcep_copy_hops(struct path_hop
*hop
);
56 /* Other static functions */
57 static void notify_status(struct path
*path
, bool not_changed
);
59 /* Module Functions */
60 static int pcep_module_finish(void);
61 static int pcep_module_late_init(struct thread_master
*tm
);
62 static int pcep_module_init(void);
64 /* ------------ Path Helper Functions ------------ */
66 struct path
*pcep_new_path(void)
69 path
= XCALLOC(MTYPE_PCEP
, sizeof(*path
));
70 path
->binding_sid
= MPLS_LABEL_NONE
;
71 path
->enforce_bandwidth
= true;
75 struct path_hop
*pcep_new_hop(void)
78 hop
= XCALLOC(MTYPE_PCEP
, sizeof(*hop
));
82 struct path_metric
*pcep_new_metric(void)
84 struct path_metric
*metric
;
85 metric
= XCALLOC(MTYPE_PCEP
, sizeof(*metric
));
89 struct path_metric
*pcep_copy_metrics(struct path_metric
*metric
)
93 struct path_metric
*new_metric
= pcep_new_metric();
94 *new_metric
= *metric
;
95 new_metric
->next
= pcep_copy_metrics(metric
->next
);
99 struct path_hop
*pcep_copy_hops(struct path_hop
*hop
)
103 struct path_hop
*new_hop
= pcep_new_hop();
105 new_hop
->next
= pcep_copy_hops(hop
->next
);
109 struct path
*pcep_copy_path(struct path
*path
)
111 struct path
*new_path
= pcep_new_path();
114 new_path
->first_metric
= pcep_copy_metrics(path
->first_metric
);
115 new_path
->first_hop
= pcep_copy_hops(path
->first_hop
);
116 if (path
->name
!= NULL
)
117 new_path
->name
= XSTRDUP(MTYPE_PCEP
, path
->name
);
118 if (path
->originator
!= NULL
)
119 new_path
->originator
= XSTRDUP(MTYPE_PCEP
, path
->originator
);
123 void pcep_free_path(struct path
*path
)
125 struct path_hop
*hop
;
126 struct path_metric
*metric
;
129 metric
= path
->first_metric
;
130 while (metric
!= NULL
) {
131 struct path_metric
*next
= metric
->next
;
132 XFREE(MTYPE_PCEP
, metric
);
135 hop
= path
->first_hop
;
136 while (hop
!= NULL
) {
137 struct path_hop
*next
= hop
->next
;
138 XFREE(MTYPE_PCEP
, hop
);
141 if (path
->originator
!= NULL
) {
142 /* The path own the memory, it is const so it is clear it
143 shouldn't be modified. XFREE macro do not support type casting
144 so we need a temporary variable */
145 tmp
= (char *)path
->originator
;
146 XFREE(MTYPE_PCEP
, tmp
);
147 path
->originator
= NULL
;
149 if (path
->name
!= NULL
) {
150 /* The path own the memory, it is const so it is clear it
151 shouldn't be modified. XFREE macro do not support type casting
152 so we need a temporary variable */
153 tmp
= (char *)path
->name
;
154 XFREE(MTYPE_PCEP
, tmp
);
157 XFREE(MTYPE_PCEP
, path
);
160 /* ------------ Other Static Functions ------------ */
162 void notify_status(struct path
*path
, bool not_changed
)
164 struct path
*resp
= NULL
;
166 if ((resp
= path_pcep_config_get_path(&path
->nbkey
))) {
167 resp
->srp_id
= path
->srp_id
;
168 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
169 "(%s) Send report for candidate path %s", __func__
,
171 pcep_ctrl_send_report(pcep_g
->fpt
, path
->pcc_id
, resp
,
176 /* ------------ Main Thread Even Handler ------------ */
178 int pcep_main_event_handler(enum pcep_main_event_type type
, int pcc_id
,
184 case PCEP_MAIN_EVENT_START_SYNC
:
185 ret
= pcep_main_event_start_sync(pcc_id
);
187 case PCEP_MAIN_EVENT_INITIATE_CANDIDATE
:
188 assert(payload
!= NULL
);
189 ret
= pcep_main_event_initiate_candidate(
190 (struct path
*)payload
);
192 case PCEP_MAIN_EVENT_UPDATE_CANDIDATE
:
193 assert(payload
!= NULL
);
194 ret
= pcep_main_event_update_candidate((struct path
*)payload
);
196 case PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
:
197 ret
= pcep_main_event_remove_candidate_segments(
198 (const char *)payload
, true);
200 case PCEP_MAIN_EVENT_UNDEFINED
:
201 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
202 "Unexpected event received in the main thread: %u",
210 int pcep_main_event_start_sync(int pcc_id
)
212 path_pcep_config_list_path(pcep_main_event_start_sync_cb
, &pcc_id
);
213 pcep_ctrl_sync_done(pcep_g
->fpt
, pcc_id
);
217 int pcep_main_event_start_sync_cb(struct path
*path
, void *arg
)
219 int *pcc_id
= (int *)arg
;
220 pcep_ctrl_sync_path(pcep_g
->fpt
, *pcc_id
, path
);
224 int pcep_main_event_initiate_candidate(struct path
*path
)
228 ret
= path_pcep_config_initiate_path(path
);
229 if (path
->do_remove
) {
230 struct pcep_error
*error
;
231 error
= XCALLOC(MTYPE_PCEP
, sizeof(*error
));
233 error
->error_type
= PCEP_ERRT_INVALID_OPERATION
;
237 PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP
;
241 PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID
;
244 error
->error_value
= PCEP_ERRV_LSP_NOT_PCE_INITIATED
;
247 zlog_warn("(%s)PCE tried to REMOVE unknown error!",
249 XFREE(MTYPE_PCEP
, error
);
250 pcep_free_path(path
);
254 pcep_ctrl_send_error(pcep_g
->fpt
, path
->pcc_id
, error
);
255 } else if (ret
!= PATH_NB_ERR
&& path
->srp_id
!= 0)
256 notify_status(path
, ret
== PATH_NB_NO_CHANGE
);
260 int pcep_main_event_update_candidate(struct path
*path
)
264 ret
= path_pcep_config_update_path(path
);
265 if (ret
!= PATH_NB_ERR
&& path
->srp_id
!= 0)
266 notify_status(path
, ret
== PATH_NB_NO_CHANGE
);
270 int pcep_main_event_remove_candidate_segments(const char *originator
,
273 srte_candidate_unset_segment_list(originator
, force
);
274 /* Avoid compiler warnings about const char* */
275 void *free_ptr
= (void *)originator
;
276 XFREE(MTYPE_PCEP
, free_ptr
);
278 srte_apply_changes();
283 /* ------------ Hook Handlers Functions Called From Main Thread ------------ */
285 int pathd_candidate_created_handler(struct srte_candidate
*candidate
)
287 struct path
*path
= candidate_to_path(candidate
);
288 int ret
= pcep_ctrl_pathd_event(pcep_g
->fpt
, PCEP_PATH_CREATED
, path
);
292 int pathd_candidate_updated_handler(struct srte_candidate
*candidate
)
294 struct path
*path
= candidate_to_path(candidate
);
295 int ret
= pcep_ctrl_pathd_event(pcep_g
->fpt
, PCEP_PATH_UPDATED
, path
);
299 int pathd_candidate_removed_handler(struct srte_candidate
*candidate
)
301 struct path
*path
= candidate_to_path(candidate
);
302 int ret
= pcep_ctrl_pathd_event(pcep_g
->fpt
, PCEP_PATH_REMOVED
, path
);
307 /* ------------ Module Functions ------------ */
309 /* this creates threads, therefore must run after fork(). but it must also
310 * run before config load, so the CLI commands don't try to touch things that
311 * aren't set up yet...
313 static int pcep_module_config_pre(struct thread_master
*tm
)
315 assert(pcep_g
->fpt
== NULL
);
316 assert(pcep_g
->master
== NULL
);
318 struct frr_pthread
*fpt
;
320 if (pcep_ctrl_initialize(tm
, &fpt
, pcep_main_event_handler
))
323 if (pcep_lib_initialize(fpt
))
332 static int pcep_module_late_init(struct thread_master
*tm
)
334 hook_register(pathd_candidate_created
, pathd_candidate_created_handler
);
335 hook_register(pathd_candidate_updated
, pathd_candidate_updated_handler
);
336 hook_register(pathd_candidate_removed
, pathd_candidate_removed_handler
);
338 hook_register(frr_config_pre
, pcep_module_config_pre
);
339 hook_register(frr_fini
, pcep_module_finish
);
346 int pcep_module_finish(void)
348 pcep_ctrl_finalize(&pcep_g
->fpt
);
351 for (int i
= 0; i
< MAX_PCC
; i
++)
352 if (pcep_g
->pce_opts_cli
[i
] != NULL
)
353 XFREE(MTYPE_PCEP
, pcep_g
->pce_opts_cli
[i
]);
358 int pcep_module_init(void)
360 pcep_g
->num_pce_opts_cli
= 0;
361 for (int i
= 0; i
< MAX_PCE
; i
++)
362 pcep_g
->pce_opts_cli
[i
] = NULL
;
363 pcep_g
->num_config_group_opts
= 0;
364 for (int i
= 0; i
< MAX_PCE
; i
++)
365 pcep_g
->config_group_opts
[i
] = NULL
;
367 hook_register(frr_late_init
, pcep_module_late_init
);
371 FRR_MODULE_SETUP(.name
= "frr_pathd_pcep", .version
= FRR_VERSION
,
372 .description
= "FRR pathd PCEP module",
373 .init
= pcep_module_init
,