]>
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> | |
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 | 29 | DEFINE_MTYPE(PATHD, PCEP, "PCEP module"); |
efba0985 SM |
30 | |
31 | /* | |
32 | * Globals. | |
33 | */ | |
34 | static struct pcep_glob pcep_glob_space = {.dbg = {0, "pathd module: pcep"}}; | |
35 | struct pcep_glob *pcep_g = &pcep_glob_space; | |
36 | ||
37 | /* Main Thread Even Handler */ | |
38 | static int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id, | |
39 | void *payload); | |
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); | |
ab7fe289 | 42 | static int pcep_main_event_initiate_candidate(struct path *path); |
efba0985 SM |
43 | static int pcep_main_event_update_candidate(struct path *path); |
44 | static int pcep_main_event_remove_candidate_segments(const char *originator, | |
45 | bool force); | |
46 | ||
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); | |
51 | ||
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); | |
55 | ||
ab7fe289 JG |
56 | /* Other static functions */ |
57 | static void notify_status(struct path *path, bool not_changed); | |
58 | ||
efba0985 SM |
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); | |
63 | ||
64 | /* ------------ Path Helper Functions ------------ */ | |
65 | ||
66 | struct 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 | ||
75 | struct path_hop *pcep_new_hop(void) | |
76 | { | |
77 | struct path_hop *hop; | |
78 | hop = XCALLOC(MTYPE_PCEP, sizeof(*hop)); | |
79 | return hop; | |
80 | } | |
81 | ||
82 | struct path_metric *pcep_new_metric(void) | |
83 | { | |
84 | struct path_metric *metric; | |
85 | metric = XCALLOC(MTYPE_PCEP, sizeof(*metric)); | |
86 | return metric; | |
87 | } | |
88 | ||
89 | struct 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 | ||
99 | struct 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 | ||
109 | struct 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 | ||
123 | void 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 | ||
162 | void 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 | ||
178 | int 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 | ||
210 | int 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 | ||
217 | int 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 |
224 | int 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 |
260 | int 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 | ||
270 | int 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 | ||
285 | int 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 | ||
292 | int 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 | ||
299 | int 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 | */ | |
313 | static int pcep_module_config_pre(struct thread_master *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 | ||
332 | static int pcep_module_late_init(struct thread_master *tm) | |
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 | ||
346 | int 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 | ||
358 | int 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 | ||
371 | FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION, | |
372 | .description = "FRR pathd PCEP module", | |
80413c20 DL |
373 | .init = pcep_module_init, |
374 | ); |