]> git.proxmox.com Git - mirror_frr.git/blame - pathd/path_pcep.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pathd / path_pcep.c
CommitLineData
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>
74971473 7#include "pceplib/pcep_utils_counters.h"
efba0985 8
c7479286 9#include "memory.h"
efba0985
SM
10#include "log.h"
11#include "command.h"
12#include "libfrr.h"
13#include "printfrr.h"
09781197 14#include "lib/version.h"
efba0985
SM
15#include "northbound.h"
16#include "frr_pthread.h"
17#include "jhash.h"
18#include "termtable.h"
19
20#include "pathd/pathd.h"
21#include "pathd/path_errors.h"
efba0985
SM
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"
ab7fe289 27#include "pathd/path_pcep_debug.h"
efba0985 28
c7479286 29DEFINE_MTYPE(PATHD, PCEP, "PCEP module");
efba0985
SM
30
31/*
32 * Globals.
33 */
34static struct pcep_glob pcep_glob_space = {.dbg = {0, "pathd module: pcep"}};
35struct pcep_glob *pcep_g = &pcep_glob_space;
36
37/* Main Thread Even Handler */
38static int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
39 void *payload);
40static int pcep_main_event_start_sync(int pcc_id);
41static int pcep_main_event_start_sync_cb(struct path *path, void *arg);
ab7fe289 42static int pcep_main_event_initiate_candidate(struct path *path);
efba0985
SM
43static int pcep_main_event_update_candidate(struct path *path);
44static int pcep_main_event_remove_candidate_segments(const char *originator,
45 bool force);
46
47/* Hook Handlers called from the Main Thread */
48static int pathd_candidate_created_handler(struct srte_candidate *candidate);
49static int pathd_candidate_updated_handler(struct srte_candidate *candidate);
50static int pathd_candidate_removed_handler(struct srte_candidate *candidate);
51
52/* Path manipulation functions */
53static struct path_metric *pcep_copy_metrics(struct path_metric *metric);
54static struct path_hop *pcep_copy_hops(struct path_hop *hop);
55
ab7fe289
JG
56/* Other static functions */
57static void notify_status(struct path *path, bool not_changed);
58
efba0985
SM
59/* Module Functions */
60static int pcep_module_finish(void);
cd9d0537 61static int pcep_module_late_init(struct event_loop *tm);
efba0985
SM
62static int pcep_module_init(void);
63
64/* ------------ Path Helper Functions ------------ */
65
66struct path *pcep_new_path(void)
67{
68 struct path *path;
69 path = XCALLOC(MTYPE_PCEP, sizeof(*path));
70 path->binding_sid = MPLS_LABEL_NONE;
71 path->enforce_bandwidth = true;
72 return path;
73}
74
75struct path_hop *pcep_new_hop(void)
76{
77 struct path_hop *hop;
78 hop = XCALLOC(MTYPE_PCEP, sizeof(*hop));
79 return hop;
80}
81
82struct path_metric *pcep_new_metric(void)
83{
84 struct path_metric *metric;
85 metric = XCALLOC(MTYPE_PCEP, sizeof(*metric));
86 return metric;
87}
88
89struct path_metric *pcep_copy_metrics(struct path_metric *metric)
90{
91 if (metric == NULL)
92 return NULL;
93 struct path_metric *new_metric = pcep_new_metric();
94 *new_metric = *metric;
95 new_metric->next = pcep_copy_metrics(metric->next);
96 return new_metric;
97}
98
99struct path_hop *pcep_copy_hops(struct path_hop *hop)
100{
101 if (hop == NULL)
102 return NULL;
103 struct path_hop *new_hop = pcep_new_hop();
104 *new_hop = *hop;
105 new_hop->next = pcep_copy_hops(hop->next);
106 return new_hop;
107}
108
109struct path *pcep_copy_path(struct path *path)
110{
111 struct path *new_path = pcep_new_path();
112
113 *new_path = *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);
120 return new_path;
121}
122
123void pcep_free_path(struct path *path)
124{
125 struct path_hop *hop;
126 struct path_metric *metric;
127 char *tmp;
128
129 metric = path->first_metric;
130 while (metric != NULL) {
131 struct path_metric *next = metric->next;
132 XFREE(MTYPE_PCEP, metric);
133 metric = next;
134 }
135 hop = path->first_hop;
136 while (hop != NULL) {
137 struct path_hop *next = hop->next;
138 XFREE(MTYPE_PCEP, hop);
139 hop = next;
140 }
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;
148 }
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);
155 path->name = NULL;
156 }
157 XFREE(MTYPE_PCEP, path);
158}
159
ab7fe289
JG
160/* ------------ Other Static Functions ------------ */
161
162void notify_status(struct path *path, bool not_changed)
163{
164 struct path *resp = NULL;
165
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__,
170 path->name);
171 pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp,
172 not_changed);
173 }
174}
efba0985
SM
175
176/* ------------ Main Thread Even Handler ------------ */
177
178int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
179 void *payload)
180{
181 int ret = 0;
182
183 switch (type) {
184 case PCEP_MAIN_EVENT_START_SYNC:
185 ret = pcep_main_event_start_sync(pcc_id);
186 break;
ab7fe289
JG
187 case PCEP_MAIN_EVENT_INITIATE_CANDIDATE:
188 assert(payload != NULL);
189 ret = pcep_main_event_initiate_candidate(
190 (struct path *)payload);
191 break;
efba0985
SM
192 case PCEP_MAIN_EVENT_UPDATE_CANDIDATE:
193 assert(payload != NULL);
194 ret = pcep_main_event_update_candidate((struct path *)payload);
195 break;
196 case PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP:
197 ret = pcep_main_event_remove_candidate_segments(
198 (const char *)payload, true);
199 break;
d5dea350 200 case PCEP_MAIN_EVENT_UNDEFINED:
efba0985
SM
201 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
202 "Unexpected event received in the main thread: %u",
203 type);
204 break;
205 }
206
207 return ret;
208}
209
210int pcep_main_event_start_sync(int pcc_id)
211{
212 path_pcep_config_list_path(pcep_main_event_start_sync_cb, &pcc_id);
213 pcep_ctrl_sync_done(pcep_g->fpt, pcc_id);
214 return 0;
215}
216
217int pcep_main_event_start_sync_cb(struct path *path, void *arg)
218{
219 int *pcc_id = (int *)arg;
220 pcep_ctrl_sync_path(pcep_g->fpt, *pcc_id, path);
221 return 1;
222}
223
ab7fe289
JG
224int pcep_main_event_initiate_candidate(struct path *path)
225{
226 int ret = 0;
227
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));
232 error->path = path;
233 error->error_type = PCEP_ERRT_INVALID_OPERATION;
234 switch (ret) {
235 case ERROR_19_1:
236 error->error_value =
237 PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP;
238 break;
239 case ERROR_19_3:
240 error->error_value =
241 PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID;
242 break;
243 case ERROR_19_9:
244 error->error_value = PCEP_ERRV_LSP_NOT_PCE_INITIATED;
245 break;
246 default:
247 zlog_warn("(%s)PCE tried to REMOVE unknown error!",
248 __func__);
249 XFREE(MTYPE_PCEP, error);
250 pcep_free_path(path);
251 return ret;
252 break;
253 }
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);
257 return ret;
258}
259
efba0985
SM
260int pcep_main_event_update_candidate(struct path *path)
261{
efba0985
SM
262 int ret = 0;
263
264 ret = path_pcep_config_update_path(path);
ab7fe289
JG
265 if (ret != PATH_NB_ERR && path->srp_id != 0)
266 notify_status(path, ret == PATH_NB_NO_CHANGE);
efba0985
SM
267 return ret;
268}
269
270int pcep_main_event_remove_candidate_segments(const char *originator,
271 bool force)
272{
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);
277
278 srte_apply_changes();
279
280 return 0;
281}
282
283/* ------------ Hook Handlers Functions Called From Main Thread ------------ */
284
285int pathd_candidate_created_handler(struct srte_candidate *candidate)
286{
287 struct path *path = candidate_to_path(candidate);
288 int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_CREATED, path);
289 return ret;
290}
291
292int pathd_candidate_updated_handler(struct srte_candidate *candidate)
293{
294 struct path *path = candidate_to_path(candidate);
295 int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_UPDATED, path);
296 return ret;
297}
298
299int pathd_candidate_removed_handler(struct srte_candidate *candidate)
300{
301 struct path *path = candidate_to_path(candidate);
302 int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_REMOVED, path);
303 return ret;
304}
305
306
307/* ------------ Module Functions ------------ */
308
159246be
DL
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...
312 */
cd9d0537 313static int pcep_module_config_pre(struct event_loop *tm)
efba0985
SM
314{
315 assert(pcep_g->fpt == NULL);
316 assert(pcep_g->master == NULL);
317
318 struct frr_pthread *fpt;
319
320 if (pcep_ctrl_initialize(tm, &fpt, pcep_main_event_handler))
321 return 1;
322
323 if (pcep_lib_initialize(fpt))
324 return 1;
325
326 pcep_g->master = tm;
327 pcep_g->fpt = fpt;
328
159246be
DL
329 return 0;
330}
331
cd9d0537 332static int pcep_module_late_init(struct event_loop *tm)
159246be 333{
efba0985
SM
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);
337
159246be 338 hook_register(frr_config_pre, pcep_module_config_pre);
efba0985
SM
339 hook_register(frr_fini, pcep_module_finish);
340
341 pcep_cli_init();
342
343 return 0;
344}
345
346int pcep_module_finish(void)
347{
348 pcep_ctrl_finalize(&pcep_g->fpt);
349 pcep_lib_finalize();
350
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]);
354
355 return 0;
356}
357
358int pcep_module_init(void)
359{
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;
366
367 hook_register(frr_late_init, pcep_module_late_init);
368 return 0;
369}
370
371FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION,
372 .description = "FRR pathd PCEP module",
80413c20
DL
373 .init = pcep_module_init,
374);