]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_config.c
Merge pull request #8987 from mobash-rasool/ospfv3-bug-fixes
[mirror_frr.git] / pathd / path_pcep_config.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
21 #include <northbound.h>
22 #include <yang.h>
23 #include <printfrr.h>
24 #include "pceplib/pcep_msg_objects.h"
25 #include "pathd/pathd.h"
26 #include "pathd/path_pcep.h"
27 #include "pathd/path_pcep_config.h"
28 #include "pathd/path_pcep_debug.h"
29 #include "thread.h"
30
31 #define MAX_XPATH 256
32 #define MAX_FLOAT_LEN 22
33 #define INETADDR4_MAXLEN 16
34 #define INETADDR6_MAXLEN 40
35 #define INITIATED_CANDIDATE_PREFERENCE 255
36 #define INITIATED_POLICY_COLOR 1
37
38
39 static void copy_candidate_objfun_info(struct srte_candidate *candidate,
40 struct path *path);
41 static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
42 struct path *path);
43 static struct path_hop *
44 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
45 static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
46 static char *candidate_name(struct srte_candidate *candidate);
47 static enum pcep_lsp_operational_status
48 status_int_to_ext(enum srte_policy_status status);
49 static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
50 static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
51
52 void path_pcep_refine_path(struct path *path)
53 {
54 struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
55 struct srte_lsp *lsp;
56
57 if (candidate == NULL)
58 return;
59
60 lsp = candidate->lsp;
61
62 if (path->name == NULL)
63 path->name = candidate_name(candidate);
64 if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
65 path->type = candidate->type;
66 if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
67 path->create_origin = candidate->protocol_origin;
68 if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
69 && (lsp->segment_list != NULL))
70 path->update_origin = lsp->segment_list->protocol_origin;
71 }
72
73 struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
74 {
75 struct srte_candidate *candidate = lookup_candidate(key);
76 if (candidate == NULL)
77 return NULL;
78 return candidate_to_path(candidate);
79 }
80
81 void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
82 {
83 struct path *path;
84 struct srte_policy *policy;
85 struct srte_candidate *candidate;
86
87 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
88 RB_FOREACH (candidate, srte_candidate_head,
89 &policy->candidate_paths) {
90 path = candidate_to_path(candidate);
91 if (!cb(path, arg))
92 return;
93 }
94 }
95 }
96
97 struct path *candidate_to_path(struct srte_candidate *candidate)
98 {
99 char *name;
100 struct path *path;
101 struct path_hop *hop = NULL;
102 struct path_metric *metric = NULL;
103 struct srte_policy *policy;
104 struct srte_lsp *lsp;
105 enum pcep_lsp_operational_status status;
106 enum srte_protocol_origin update_origin = 0;
107 char *originator = NULL;
108
109 policy = candidate->policy;
110 lsp = candidate->lsp;
111
112 if (lsp->segment_list != NULL) {
113 hop = path_pcep_config_list_path_hops(lsp->segment_list);
114 update_origin = lsp->segment_list->protocol_origin;
115 originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
116 }
117 path = pcep_new_path();
118 name = candidate_name(candidate);
119 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
120 status = status_int_to_ext(policy->status);
121 } else {
122 status = PCEP_LSP_OPERATIONAL_DOWN;
123 }
124 for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
125 struct path_metric *path_metric;
126 struct srte_metric *srte_metric = &lsp->metrics[i];
127 if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
128 path_metric = pcep_new_metric();
129 path_metric->next = metric;
130 metric = path_metric;
131 metric->type = i + 1;
132 metric->value = srte_metric->value;
133 metric->enforce = CHECK_FLAG(srte_metric->flags,
134 F_METRIC_IS_REQUIRED);
135 metric->is_bound = CHECK_FLAG(srte_metric->flags,
136 F_METRIC_IS_BOUND);
137 metric->is_computed = CHECK_FLAG(srte_metric->flags,
138 F_METRIC_IS_COMPUTED);
139 }
140 }
141 *path = (struct path){
142 .nbkey = (struct lsp_nb_key){.color = policy->color,
143 .endpoint = policy->endpoint,
144 .preference =
145 candidate->preference},
146 .create_origin = lsp->protocol_origin,
147 .update_origin = update_origin,
148 .originator = originator,
149 .plsp_id = 0,
150 .name = name,
151 .type = candidate->type,
152 .srp_id = policy->srp_id,
153 .req_id = 0,
154 .binding_sid = policy->binding_sid,
155 .status = status,
156 .do_remove = false,
157 .go_active = false,
158 .was_created = false,
159 .was_removed = false,
160 .is_synching = false,
161 .is_delegated = false,
162 .first_hop = hop,
163 .first_metric = metric};
164
165 path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
166 if (path->has_bandwidth) {
167 path->enforce_bandwidth =
168 CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
169 path->bandwidth = lsp->bandwidth;
170 } else {
171 path->enforce_bandwidth = true;
172 path->bandwidth = 0;
173 }
174
175 copy_candidate_objfun_info(candidate, path);
176 copy_candidate_affinity_filters(candidate, path);
177
178 return path;
179 }
180
181 void copy_candidate_objfun_info(struct srte_candidate *candidate,
182 struct path *path)
183 {
184 struct srte_lsp *lsp = candidate->lsp;
185
186 if (lsp != NULL) {
187 if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
188 path->has_pce_objfun = true;
189 path->pce_objfun = lsp->objfun;
190 } else {
191 path->has_pce_objfun = false;
192 path->pce_objfun = OBJFUN_UNDEFINED;
193 }
194 }
195 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
196 path->has_pcc_objfun = true;
197 path->pcc_objfun = candidate->objfun;
198 path->enforce_pcc_objfun = CHECK_FLAG(
199 candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
200
201 } else {
202 path->has_pcc_objfun = false;
203 path->pcc_objfun = OBJFUN_UNDEFINED;
204 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
205 }
206 }
207
208 void copy_candidate_affinity_filters(struct srte_candidate *candidate,
209 struct path *path)
210 {
211 bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
212 bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
213 bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
214 path->has_affinity_filters = eany || iany || iall;
215 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
216 eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
217 - 1]
218 : 0;
219 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
220 iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
221 - 1]
222 : 0;
223 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
224 iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
225 - 1]
226 : 0;
227 }
228
229 struct path_hop *
230 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
231 {
232 struct srte_segment_entry *segment;
233 struct path_hop *hop = NULL, *last_hop = NULL;
234
235 RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
236 &segment_list->segments) {
237 hop = pcep_new_hop();
238 *hop = (struct path_hop){
239 .next = last_hop,
240 .is_loose = false,
241 .has_sid = true,
242 .is_mpls = true,
243 .has_attribs = false,
244 .sid = {.mpls = {.label = segment->sid_value}},
245 .has_nai =
246 segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
247 .nai = {.type = pcep_nai_type(segment->nai_type)}};
248 switch (segment->nai_type) {
249 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
250 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
251 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
252 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
253 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
254 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
255 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
256 sizeof(struct ipaddr));
257 break;
258 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
259 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
260 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
261 sizeof(struct ipaddr));
262 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
263 sizeof(struct ipaddr));
264 break;
265 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
266 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
267 sizeof(struct ipaddr));
268 hop->nai.local_iface = segment->nai_local_iface;
269 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
270 sizeof(struct ipaddr));
271 hop->nai.remote_iface = segment->nai_remote_iface;
272 break;
273 default:
274 break;
275 }
276 last_hop = hop;
277 }
278 return hop;
279 }
280
281 int path_pcep_config_initiate_path(struct path *path)
282 {
283 struct srte_policy *policy;
284 struct srte_candidate *candidate;
285
286 if (path->do_remove) {
287 zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
288 path->originator);
289 candidate = lookup_candidate(&path->nbkey);
290 if (candidate) {
291 if (!path->is_delegated) {
292 zlog_warn(
293 "(%s)PCE tried to REMOVE but it's not Delegated!",
294 __func__);
295 return ERROR_19_1;
296 }
297 if (candidate->type != SRTE_CANDIDATE_TYPE_DYNAMIC) {
298 zlog_warn(
299 "(%s)PCE tried to REMOVE but it's not PCE origin!",
300 __func__);
301 return ERROR_19_9;
302 }
303 zlog_warn(
304 "(%s)PCE tried to REMOVE found canidate!, let's remove",
305 __func__);
306 candidate->policy->srp_id = path->srp_id;
307 SET_FLAG(candidate->policy->flags, F_POLICY_DELETED);
308 SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
309 } else {
310 zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
311 __func__);
312 return ERROR_19_3;
313 }
314 srte_apply_changes();
315 } else {
316 assert(!IS_IPADDR_NONE(&path->nbkey.endpoint));
317
318 if (path->nbkey.preference == 0)
319 path->nbkey.preference = INITIATED_CANDIDATE_PREFERENCE;
320
321 if (path->nbkey.color == 0)
322 path->nbkey.color = INITIATED_POLICY_COLOR;
323
324 candidate = lookup_candidate(&path->nbkey);
325 if (!candidate) {
326 policy = srte_policy_add(
327 path->nbkey.color, &path->nbkey.endpoint,
328 SRTE_ORIGIN_PCEP, path->originator);
329 strlcpy(policy->name, path->name, sizeof(policy->name));
330 policy->binding_sid = path->binding_sid;
331 SET_FLAG(policy->flags, F_POLICY_NEW);
332 candidate = srte_candidate_add(
333 policy, path->nbkey.preference,
334 SRTE_ORIGIN_PCEP, path->originator);
335 candidate->policy->srp_id = path->srp_id;
336 strlcpy(candidate->name, path->name,
337 sizeof(candidate->name));
338 SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
339 } else {
340 policy = candidate->policy;
341 if ((path->originator != candidate->originator)
342 || (path->originator != policy->originator)) {
343 /* There is already an initiated path from
344 * another PCE, show a warning and regect the
345 * initiated path */
346 zlog_warn(
347 "PCE %s tried to initiate a path already initiated by PCE %s",
348 path->originator,
349 candidate->originator);
350 return 1;
351 }
352 if ((policy->protocol_origin != SRTE_ORIGIN_PCEP)
353 || (candidate->protocol_origin
354 != SRTE_ORIGIN_PCEP)) {
355 /* There is already an initiated path from
356 * another PCE, show a warning and regect the
357 * initiated path */
358 zlog_warn(
359 "PCE %s tried to initiate a path created localy",
360 path->originator);
361 return 1;
362 }
363 }
364 return path_pcep_config_update_path(path);
365 }
366 return 0;
367 }
368
369 int path_pcep_config_update_path(struct path *path)
370 {
371 assert(path != NULL);
372 assert(path->nbkey.preference != 0);
373 assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
374
375 int number_of_sid_clashed = 0;
376 struct path_hop *hop;
377 struct path_metric *metric;
378 int index;
379 char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
380 char *segment_list_name = NULL;
381 struct srte_candidate *candidate;
382 struct srte_segment_list *segment_list = NULL;
383 struct srte_segment_entry *segment;
384
385 candidate = lookup_candidate(&path->nbkey);
386
387 // if there is no candidate to update we are done
388 if (!candidate)
389 return 0;
390
391 candidate->policy->srp_id = path->srp_id;
392 // first clean up old segment list if present
393 if (candidate->lsp->segment_list) {
394 SET_FLAG(candidate->lsp->segment_list->flags,
395 F_SEGMENT_LIST_DELETED);
396 srte_segment_list_del(candidate->lsp->segment_list);
397 candidate->lsp->segment_list = NULL;
398 }
399
400 if (path->first_hop == NULL)
401 return PATH_NB_ERR;
402
403 snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
404 "%s-%u", path->name, path->plsp_id);
405 segment_list_name = segment_list_name_buff;
406
407 segment_list = srte_segment_list_add(segment_list_name);
408 segment_list->protocol_origin = path->update_origin;
409 strlcpy(segment_list->originator, path->originator,
410 sizeof(segment_list->originator));
411 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
412 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
413
414 for (hop = path->first_hop, index = 10; hop != NULL;
415 hop = hop->next, index += 10) {
416 assert(hop->has_sid);
417 assert(hop->is_mpls);
418
419 segment = srte_segment_entry_add(segment_list, index);
420
421 segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
422 SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
423
424 if (!hop->has_nai)
425 continue;
426 if (srte_segment_entry_set_nai(
427 segment, srte_nai_type(hop->nai.type),
428 &hop->nai.local_addr, hop->nai.local_iface,
429 &hop->nai.remote_addr, hop->nai.remote_iface, 0, 0)
430 == PATH_SID_ERROR)
431 /* TED queries don't match PCE */
432 /* Don't apply srte,zebra changes */
433 number_of_sid_clashed++;
434 }
435
436 candidate->lsp->segment_list = segment_list;
437 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
438
439 for (metric = path->first_metric; metric != NULL; metric = metric->next)
440 srte_lsp_set_metric(
441 candidate->lsp,
442 (enum srte_candidate_metric_type)metric->type,
443 metric->value, metric->enforce, metric->is_bound,
444 metric->is_computed);
445
446 if (path->has_bandwidth)
447 srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
448 path->enforce_bandwidth);
449
450 if (path->has_pce_objfun) {
451 SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
452 candidate->lsp->objfun = path->pce_objfun;
453 }
454
455 if (number_of_sid_clashed)
456 SET_FLAG(segment->segment_list->flags,
457 F_SEGMENT_LIST_SID_CONFLICT);
458 else
459 srte_apply_changes();
460
461 return 0;
462 }
463
464 struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
465 {
466 struct srte_policy *policy = NULL;
467 policy = srte_policy_find(key->color, &key->endpoint);
468 if (policy == NULL)
469 return NULL;
470 return srte_candidate_find(policy, key->preference);
471 }
472
473 char *candidate_name(struct srte_candidate *candidate)
474 {
475 if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
476 || candidate->protocol_origin == SRTE_ORIGIN_BGP)
477 return asprintfrr(MTYPE_PCEP, "%s", candidate->policy->name);
478 else
479 return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
480 candidate->name);
481 }
482
483 enum pcep_lsp_operational_status
484 status_int_to_ext(enum srte_policy_status status)
485 {
486 switch (status) {
487 case SRTE_POLICY_STATUS_UP:
488 return PCEP_LSP_OPERATIONAL_ACTIVE;
489 case SRTE_POLICY_STATUS_GOING_UP:
490 return PCEP_LSP_OPERATIONAL_GOING_UP;
491 case SRTE_POLICY_STATUS_GOING_DOWN:
492 return PCEP_LSP_OPERATIONAL_GOING_DOWN;
493 default:
494 return PCEP_LSP_OPERATIONAL_DOWN;
495 }
496 }
497
498 enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
499 {
500 switch (type) {
501 case SRTE_SEGMENT_NAI_TYPE_NONE:
502 return PCEP_SR_SUBOBJ_NAI_ABSENT;
503 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
504 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
505 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
506 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
507 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
508 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
509 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
510 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
511 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
512 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
513 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
514 return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY;
515 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
516 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
517 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
518 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
519 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
520 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
521 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
522 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
523 default:
524 return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
525 }
526 }
527
528 enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
529 {
530 switch (type) {
531 case PCEP_SR_SUBOBJ_NAI_ABSENT:
532 return SRTE_SEGMENT_NAI_TYPE_NONE;
533 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
534 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
535 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
536 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
537 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
538 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
539 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
540 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
541 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
542 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
543 default:
544 return SRTE_SEGMENT_NAI_TYPE_NONE;
545 }
546 }