]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep.c
Merge pull request #8912 from gpnaveen/ospf_asbr_summary
[mirror_frr.git] / pathd / path_pcep.c
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 #include "pceplib/pcep_utils_counters.h"
21
22 #include "memory.h"
23 #include "log.h"
24 #include "command.h"
25 #include "libfrr.h"
26 #include "printfrr.h"
27 #include "lib/version.h"
28 #include "northbound.h"
29 #include "frr_pthread.h"
30 #include "jhash.h"
31 #include "termtable.h"
32
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"
41
42 DEFINE_MTYPE(PATHD, PCEP, "PCEP module");
43
44 /*
45 * Globals.
46 */
47 static struct pcep_glob pcep_glob_space = {.dbg = {0, "pathd module: pcep"}};
48 struct pcep_glob *pcep_g = &pcep_glob_space;
49
50 /* Main Thread Even Handler */
51 static int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
52 void *payload);
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,
58 bool force);
59
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);
64
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);
68
69 /* Other static functions */
70 static void notify_status(struct path *path, bool not_changed);
71
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);
76
77 /* ------------ Path Helper Functions ------------ */
78
79 struct path *pcep_new_path(void)
80 {
81 struct path *path;
82 path = XCALLOC(MTYPE_PCEP, sizeof(*path));
83 path->binding_sid = MPLS_LABEL_NONE;
84 path->enforce_bandwidth = true;
85 return path;
86 }
87
88 struct path_hop *pcep_new_hop(void)
89 {
90 struct path_hop *hop;
91 hop = XCALLOC(MTYPE_PCEP, sizeof(*hop));
92 return hop;
93 }
94
95 struct path_metric *pcep_new_metric(void)
96 {
97 struct path_metric *metric;
98 metric = XCALLOC(MTYPE_PCEP, sizeof(*metric));
99 return metric;
100 }
101
102 struct path_metric *pcep_copy_metrics(struct path_metric *metric)
103 {
104 if (metric == NULL)
105 return NULL;
106 struct path_metric *new_metric = pcep_new_metric();
107 *new_metric = *metric;
108 new_metric->next = pcep_copy_metrics(metric->next);
109 return new_metric;
110 }
111
112 struct path_hop *pcep_copy_hops(struct path_hop *hop)
113 {
114 if (hop == NULL)
115 return NULL;
116 struct path_hop *new_hop = pcep_new_hop();
117 *new_hop = *hop;
118 new_hop->next = pcep_copy_hops(hop->next);
119 return new_hop;
120 }
121
122 struct path *pcep_copy_path(struct path *path)
123 {
124 struct path *new_path = pcep_new_path();
125
126 *new_path = *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);
133 return new_path;
134 }
135
136 void pcep_free_path(struct path *path)
137 {
138 struct path_hop *hop;
139 struct path_metric *metric;
140 char *tmp;
141
142 metric = path->first_metric;
143 while (metric != NULL) {
144 struct path_metric *next = metric->next;
145 XFREE(MTYPE_PCEP, metric);
146 metric = next;
147 }
148 hop = path->first_hop;
149 while (hop != NULL) {
150 struct path_hop *next = hop->next;
151 XFREE(MTYPE_PCEP, hop);
152 hop = next;
153 }
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;
161 }
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);
168 path->name = NULL;
169 }
170 XFREE(MTYPE_PCEP, path);
171 }
172
173 /* ------------ Other Static Functions ------------ */
174
175 void notify_status(struct path *path, bool not_changed)
176 {
177 struct path *resp = NULL;
178
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__,
183 path->name);
184 pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp,
185 not_changed);
186 }
187 }
188
189 /* ------------ Main Thread Even Handler ------------ */
190
191 int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
192 void *payload)
193 {
194 int ret = 0;
195
196 switch (type) {
197 case PCEP_MAIN_EVENT_START_SYNC:
198 ret = pcep_main_event_start_sync(pcc_id);
199 break;
200 case PCEP_MAIN_EVENT_INITIATE_CANDIDATE:
201 assert(payload != NULL);
202 ret = pcep_main_event_initiate_candidate(
203 (struct path *)payload);
204 break;
205 case PCEP_MAIN_EVENT_UPDATE_CANDIDATE:
206 assert(payload != NULL);
207 ret = pcep_main_event_update_candidate((struct path *)payload);
208 break;
209 case PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP:
210 ret = pcep_main_event_remove_candidate_segments(
211 (const char *)payload, true);
212 break;
213 default:
214 flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
215 "Unexpected event received in the main thread: %u",
216 type);
217 break;
218 }
219
220 return ret;
221 }
222
223 int pcep_main_event_start_sync(int pcc_id)
224 {
225 path_pcep_config_list_path(pcep_main_event_start_sync_cb, &pcc_id);
226 pcep_ctrl_sync_done(pcep_g->fpt, pcc_id);
227 return 0;
228 }
229
230 int pcep_main_event_start_sync_cb(struct path *path, void *arg)
231 {
232 int *pcc_id = (int *)arg;
233 pcep_ctrl_sync_path(pcep_g->fpt, *pcc_id, path);
234 return 1;
235 }
236
237 int pcep_main_event_initiate_candidate(struct path *path)
238 {
239 int ret = 0;
240
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));
245 error->path = path;
246 error->error_type = PCEP_ERRT_INVALID_OPERATION;
247 switch (ret) {
248 case ERROR_19_1:
249 error->error_value =
250 PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP;
251 break;
252 case ERROR_19_3:
253 error->error_value =
254 PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID;
255 break;
256 case ERROR_19_9:
257 error->error_value = PCEP_ERRV_LSP_NOT_PCE_INITIATED;
258 break;
259 default:
260 zlog_warn("(%s)PCE tried to REMOVE unknown error!",
261 __func__);
262 XFREE(MTYPE_PCEP, error);
263 pcep_free_path(path);
264 return ret;
265 break;
266 }
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);
270 return ret;
271 }
272
273 int pcep_main_event_update_candidate(struct path *path)
274 {
275 int ret = 0;
276
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);
280 return ret;
281 }
282
283 int pcep_main_event_remove_candidate_segments(const char *originator,
284 bool force)
285 {
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);
290
291 srte_apply_changes();
292
293 return 0;
294 }
295
296 /* ------------ Hook Handlers Functions Called From Main Thread ------------ */
297
298 int pathd_candidate_created_handler(struct srte_candidate *candidate)
299 {
300 struct path *path = candidate_to_path(candidate);
301 int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_CREATED, path);
302 return ret;
303 }
304
305 int pathd_candidate_updated_handler(struct srte_candidate *candidate)
306 {
307 struct path *path = candidate_to_path(candidate);
308 int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_UPDATED, path);
309 return ret;
310 }
311
312 int pathd_candidate_removed_handler(struct srte_candidate *candidate)
313 {
314 struct path *path = candidate_to_path(candidate);
315 int ret = pcep_ctrl_pathd_event(pcep_g->fpt, PCEP_PATH_REMOVED, path);
316 return ret;
317 }
318
319
320 /* ------------ Module Functions ------------ */
321
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...
325 */
326 static int pcep_module_config_pre(struct thread_master *tm)
327 {
328 assert(pcep_g->fpt == NULL);
329 assert(pcep_g->master == NULL);
330
331 struct frr_pthread *fpt;
332
333 if (pcep_ctrl_initialize(tm, &fpt, pcep_main_event_handler))
334 return 1;
335
336 if (pcep_lib_initialize(fpt))
337 return 1;
338
339 pcep_g->master = tm;
340 pcep_g->fpt = fpt;
341
342 return 0;
343 }
344
345 static int pcep_module_late_init(struct thread_master *tm)
346 {
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);
350
351 hook_register(frr_config_pre, pcep_module_config_pre);
352 hook_register(frr_fini, pcep_module_finish);
353
354 pcep_cli_init();
355
356 return 0;
357 }
358
359 int pcep_module_finish(void)
360 {
361 pcep_ctrl_finalize(&pcep_g->fpt);
362 pcep_lib_finalize();
363
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]);
367
368 return 0;
369 }
370
371 int pcep_module_init(void)
372 {
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;
379
380 hook_register(frr_late_init, pcep_module_late_init);
381 return 0;
382 }
383
384 FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION,
385 .description = "FRR pathd PCEP module",
386 .init = pcep_module_init,
387 );