2 * Copyright (C) 2020 NetDEF, Inc.
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)
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
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
20 #include "pceplib/pcep_utils_counters.h"
27 #include "lib/version.h"
28 #include "northbound.h"
29 #include "frr_pthread.h"
31 #include "termtable.h"
33 #include "pathd/pathd.h"
34 #include "pathd/path_errors.h"
35 #include "pathd/path_pcep.h"
36 #include "pathd/path_pcep_cli.h"
37 #include "pathd/path_pcep_controller.h"
38 #include "pathd/path_pcep_lib.h"
39 #include "pathd/path_pcep_config.h"
40 #include "pathd/path_pcep_debug.h"
42 DEFINE_MTYPE(PATHD
, PCEP
, "PCEP module");
47 static struct pcep_glob pcep_glob_space
= {.dbg
= {0, "pathd module: pcep"}};
48 struct pcep_glob
*pcep_g
= &pcep_glob_space
;
50 /* Main Thread Even Handler */
51 static int pcep_main_event_handler(enum pcep_main_event_type type
, int pcc_id
,
53 static int pcep_main_event_start_sync(int pcc_id
);
54 static int pcep_main_event_start_sync_cb(struct path
*path
, void *arg
);
55 static int pcep_main_event_initiate_candidate(struct path
*path
);
56 static int pcep_main_event_update_candidate(struct path
*path
);
57 static int pcep_main_event_remove_candidate_segments(const char *originator
,
60 /* Hook Handlers called from the Main Thread */
61 static int pathd_candidate_created_handler(struct srte_candidate
*candidate
);
62 static int pathd_candidate_updated_handler(struct srte_candidate
*candidate
);
63 static int pathd_candidate_removed_handler(struct srte_candidate
*candidate
);
65 /* Path manipulation functions */
66 static struct path_metric
*pcep_copy_metrics(struct path_metric
*metric
);
67 static struct path_hop
*pcep_copy_hops(struct path_hop
*hop
);
69 /* Other static functions */
70 static void notify_status(struct path
*path
, bool not_changed
);
72 /* Module Functions */
73 static int pcep_module_finish(void);
74 static int pcep_module_late_init(struct thread_master
*tm
);
75 static int pcep_module_init(void);
77 /* ------------ Path Helper Functions ------------ */
79 struct path
*pcep_new_path(void)
82 path
= XCALLOC(MTYPE_PCEP
, sizeof(*path
));
83 path
->binding_sid
= MPLS_LABEL_NONE
;
84 path
->enforce_bandwidth
= true;
88 struct path_hop
*pcep_new_hop(void)
91 hop
= XCALLOC(MTYPE_PCEP
, sizeof(*hop
));
95 struct path_metric
*pcep_new_metric(void)
97 struct path_metric
*metric
;
98 metric
= XCALLOC(MTYPE_PCEP
, sizeof(*metric
));
102 struct path_metric
*pcep_copy_metrics(struct path_metric
*metric
)
106 struct path_metric
*new_metric
= pcep_new_metric();
107 *new_metric
= *metric
;
108 new_metric
->next
= pcep_copy_metrics(metric
->next
);
112 struct path_hop
*pcep_copy_hops(struct path_hop
*hop
)
116 struct path_hop
*new_hop
= pcep_new_hop();
118 new_hop
->next
= pcep_copy_hops(hop
->next
);
122 struct path
*pcep_copy_path(struct path
*path
)
124 struct path
*new_path
= pcep_new_path();
127 new_path
->first_metric
= pcep_copy_metrics(path
->first_metric
);
128 new_path
->first_hop
= pcep_copy_hops(path
->first_hop
);
129 if (path
->name
!= NULL
)
130 new_path
->name
= XSTRDUP(MTYPE_PCEP
, path
->name
);
131 if (path
->originator
!= NULL
)
132 new_path
->originator
= XSTRDUP(MTYPE_PCEP
, path
->originator
);
136 void pcep_free_path(struct path
*path
)
138 struct path_hop
*hop
;
139 struct path_metric
*metric
;
142 metric
= path
->first_metric
;
143 while (metric
!= NULL
) {
144 struct path_metric
*next
= metric
->next
;
145 XFREE(MTYPE_PCEP
, metric
);
148 hop
= path
->first_hop
;
149 while (hop
!= NULL
) {
150 struct path_hop
*next
= hop
->next
;
151 XFREE(MTYPE_PCEP
, hop
);
154 if (path
->originator
!= NULL
) {
155 /* The path own the memory, it is const so it is clear it
156 shouldn't be modified. XFREE macro do not support type casting
157 so we need a temporary variable */
158 tmp
= (char *)path
->originator
;
159 XFREE(MTYPE_PCEP
, tmp
);
160 path
->originator
= NULL
;
162 if (path
->name
!= NULL
) {
163 /* The path own the memory, it is const so it is clear it
164 shouldn't be modified. XFREE macro do not support type casting
165 so we need a temporary variable */
166 tmp
= (char *)path
->name
;
167 XFREE(MTYPE_PCEP
, tmp
);
170 XFREE(MTYPE_PCEP
, path
);
173 /* ------------ Other Static Functions ------------ */
175 void notify_status(struct path
*path
, bool not_changed
)
177 struct path
*resp
= NULL
;
179 if ((resp
= path_pcep_config_get_path(&path
->nbkey
))) {
180 resp
->srp_id
= path
->srp_id
;
181 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
182 "(%s) Send report for candidate path %s", __func__
,
184 pcep_ctrl_send_report(pcep_g
->fpt
, path
->pcc_id
, resp
,
189 /* ------------ Main Thread Even Handler ------------ */
191 int pcep_main_event_handler(enum pcep_main_event_type type
, int pcc_id
,
197 case PCEP_MAIN_EVENT_START_SYNC
:
198 ret
= pcep_main_event_start_sync(pcc_id
);
200 case PCEP_MAIN_EVENT_INITIATE_CANDIDATE
:
201 assert(payload
!= NULL
);
202 ret
= pcep_main_event_initiate_candidate(
203 (struct path
*)payload
);
205 case PCEP_MAIN_EVENT_UPDATE_CANDIDATE
:
206 assert(payload
!= NULL
);
207 ret
= pcep_main_event_update_candidate((struct path
*)payload
);
209 case PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
:
210 ret
= pcep_main_event_remove_candidate_segments(
211 (const char *)payload
, true);
214 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR
,
215 "Unexpected event received in the main thread: %u",
223 int pcep_main_event_start_sync(int pcc_id
)
225 path_pcep_config_list_path(pcep_main_event_start_sync_cb
, &pcc_id
);
226 pcep_ctrl_sync_done(pcep_g
->fpt
, pcc_id
);
230 int pcep_main_event_start_sync_cb(struct path
*path
, void *arg
)
232 int *pcc_id
= (int *)arg
;
233 pcep_ctrl_sync_path(pcep_g
->fpt
, *pcc_id
, path
);
237 int pcep_main_event_initiate_candidate(struct path
*path
)
241 ret
= path_pcep_config_initiate_path(path
);
242 if (path
->do_remove
) {
243 struct pcep_error
*error
;
244 error
= XCALLOC(MTYPE_PCEP
, sizeof(*error
));
246 error
->error_type
= PCEP_ERRT_INVALID_OPERATION
;
250 PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP
;
254 PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID
;
257 error
->error_value
= PCEP_ERRV_LSP_NOT_PCE_INITIATED
;
260 zlog_warn("(%s)PCE tried to REMOVE unknown error!",
262 XFREE(MTYPE_PCEP
, error
);
263 pcep_free_path(path
);
267 pcep_ctrl_send_error(pcep_g
->fpt
, path
->pcc_id
, error
);
268 } else if (ret
!= PATH_NB_ERR
&& path
->srp_id
!= 0)
269 notify_status(path
, ret
== PATH_NB_NO_CHANGE
);
273 int pcep_main_event_update_candidate(struct path
*path
)
277 ret
= path_pcep_config_update_path(path
);
278 if (ret
!= PATH_NB_ERR
&& path
->srp_id
!= 0)
279 notify_status(path
, ret
== PATH_NB_NO_CHANGE
);
283 int pcep_main_event_remove_candidate_segments(const char *originator
,
286 srte_candidate_unset_segment_list(originator
, force
);
287 /* Avoid compiler warnings about const char* */
288 void *free_ptr
= (void *)originator
;
289 XFREE(MTYPE_PCEP
, free_ptr
);
291 srte_apply_changes();
296 /* ------------ Hook Handlers Functions Called From Main Thread ------------ */
298 int pathd_candidate_created_handler(struct srte_candidate
*candidate
)
300 struct path
*path
= candidate_to_path(candidate
);
301 int ret
= pcep_ctrl_pathd_event(pcep_g
->fpt
, PCEP_PATH_CREATED
, path
);
305 int pathd_candidate_updated_handler(struct srte_candidate
*candidate
)
307 struct path
*path
= candidate_to_path(candidate
);
308 int ret
= pcep_ctrl_pathd_event(pcep_g
->fpt
, PCEP_PATH_UPDATED
, path
);
312 int pathd_candidate_removed_handler(struct srte_candidate
*candidate
)
314 struct path
*path
= candidate_to_path(candidate
);
315 int ret
= pcep_ctrl_pathd_event(pcep_g
->fpt
, PCEP_PATH_REMOVED
, path
);
320 /* ------------ Module Functions ------------ */
322 /* this creates threads, therefore must run after fork(). but it must also
323 * run before config load, so the CLI commands don't try to touch things that
324 * aren't set up yet...
326 static int pcep_module_config_pre(struct thread_master
*tm
)
328 assert(pcep_g
->fpt
== NULL
);
329 assert(pcep_g
->master
== NULL
);
331 struct frr_pthread
*fpt
;
333 if (pcep_ctrl_initialize(tm
, &fpt
, pcep_main_event_handler
))
336 if (pcep_lib_initialize(fpt
))
345 static int pcep_module_late_init(struct thread_master
*tm
)
347 hook_register(pathd_candidate_created
, pathd_candidate_created_handler
);
348 hook_register(pathd_candidate_updated
, pathd_candidate_updated_handler
);
349 hook_register(pathd_candidate_removed
, pathd_candidate_removed_handler
);
351 hook_register(frr_config_pre
, pcep_module_config_pre
);
352 hook_register(frr_fini
, pcep_module_finish
);
359 int pcep_module_finish(void)
361 pcep_ctrl_finalize(&pcep_g
->fpt
);
364 for (int i
= 0; i
< MAX_PCC
; i
++)
365 if (pcep_g
->pce_opts_cli
[i
] != NULL
)
366 XFREE(MTYPE_PCEP
, pcep_g
->pce_opts_cli
[i
]);
371 int pcep_module_init(void)
373 pcep_g
->num_pce_opts_cli
= 0;
374 for (int i
= 0; i
< MAX_PCE
; i
++)
375 pcep_g
->pce_opts_cli
[i
] = NULL
;
376 pcep_g
->num_config_group_opts
= 0;
377 for (int i
= 0; i
< MAX_PCE
; i
++)
378 pcep_g
->config_group_opts
[i
] = NULL
;
380 hook_register(frr_late_init
, pcep_module_late_init
);
384 FRR_MODULE_SETUP(.name
= "frr_pathd_pcep", .version
= FRR_VERSION
,
385 .description
= "FRR pathd PCEP module",
386 .init
= pcep_module_init
,