]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_config.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[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 case SRTE_SEGMENT_NAI_TYPE_NONE:
274 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
275 break;
276 }
277 last_hop = hop;
278 }
279 return hop;
280 }
281
282 int path_pcep_config_initiate_path(struct path *path)
283 {
284 struct srte_policy *policy;
285 struct srte_candidate *candidate;
286
287 if (path->do_remove) {
288 zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
289 path->originator);
290 candidate = lookup_candidate(&path->nbkey);
291 if (candidate) {
292 if (!path->is_delegated) {
293 zlog_warn(
294 "(%s)PCE tried to REMOVE but it's not Delegated!",
295 __func__);
296 return ERROR_19_1;
297 }
298 if (candidate->type != SRTE_CANDIDATE_TYPE_DYNAMIC) {
299 zlog_warn(
300 "(%s)PCE tried to REMOVE but it's not PCE origin!",
301 __func__);
302 return ERROR_19_9;
303 }
304 zlog_warn(
305 "(%s)PCE tried to REMOVE found candidate!, let's remove",
306 __func__);
307 candidate->policy->srp_id = path->srp_id;
308 SET_FLAG(candidate->policy->flags, F_POLICY_DELETED);
309 SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
310 } else {
311 zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
312 __func__);
313 return ERROR_19_3;
314 }
315 srte_apply_changes();
316 } else {
317 assert(!IS_IPADDR_NONE(&path->nbkey.endpoint));
318
319 if (path->nbkey.preference == 0)
320 path->nbkey.preference = INITIATED_CANDIDATE_PREFERENCE;
321
322 if (path->nbkey.color == 0)
323 path->nbkey.color = INITIATED_POLICY_COLOR;
324
325 candidate = lookup_candidate(&path->nbkey);
326 if (!candidate) {
327 policy = srte_policy_add(
328 path->nbkey.color, &path->nbkey.endpoint,
329 SRTE_ORIGIN_PCEP, path->originator);
330 strlcpy(policy->name, path->name, sizeof(policy->name));
331 policy->binding_sid = path->binding_sid;
332 SET_FLAG(policy->flags, F_POLICY_NEW);
333 candidate = srte_candidate_add(
334 policy, path->nbkey.preference,
335 SRTE_ORIGIN_PCEP, path->originator);
336 candidate->policy->srp_id = path->srp_id;
337 strlcpy(candidate->name, path->name,
338 sizeof(candidate->name));
339 SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
340 } else {
341 policy = candidate->policy;
342 if ((path->originator != candidate->originator)
343 || (path->originator != policy->originator)) {
344 /* There is already an initiated path from
345 * another PCE, show a warning and regect the
346 * initiated path */
347 zlog_warn(
348 "PCE %s tried to initiate a path already initiated by PCE %s",
349 path->originator,
350 candidate->originator);
351 return 1;
352 }
353 if ((policy->protocol_origin != SRTE_ORIGIN_PCEP)
354 || (candidate->protocol_origin
355 != SRTE_ORIGIN_PCEP)) {
356 /* There is already an initiated path from
357 * another PCE, show a warning and regect the
358 * initiated path */
359 zlog_warn(
360 "PCE %s tried to initiate a path created localy",
361 path->originator);
362 return 1;
363 }
364 }
365 return path_pcep_config_update_path(path);
366 }
367 return 0;
368 }
369
370 int path_pcep_config_update_path(struct path *path)
371 {
372 assert(path != NULL);
373 assert(path->nbkey.preference != 0);
374 assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
375
376 int number_of_sid_clashed = 0;
377 struct path_hop *hop;
378 struct path_metric *metric;
379 int index;
380 char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
381 char *segment_list_name = NULL;
382 struct srte_candidate *candidate;
383 struct srte_segment_list *segment_list = NULL;
384 struct srte_segment_entry *segment;
385
386 candidate = lookup_candidate(&path->nbkey);
387
388 // if there is no candidate to update we are done
389 if (!candidate)
390 return 0;
391
392 candidate->policy->srp_id = path->srp_id;
393 // first clean up old segment list if present
394 if (candidate->lsp->segment_list) {
395 SET_FLAG(candidate->lsp->segment_list->flags,
396 F_SEGMENT_LIST_DELETED);
397 srte_segment_list_del(candidate->lsp->segment_list);
398 candidate->lsp->segment_list = NULL;
399 }
400
401 if (path->first_hop == NULL)
402 return PATH_NB_ERR;
403
404 snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
405 "%s-%u", path->name, path->plsp_id);
406 segment_list_name = segment_list_name_buff;
407
408 segment_list = srte_segment_list_add(segment_list_name);
409 segment_list->protocol_origin = path->update_origin;
410 strlcpy(segment_list->originator, path->originator,
411 sizeof(segment_list->originator));
412 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
413 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
414
415 for (hop = path->first_hop, index = 10; hop != NULL;
416 hop = hop->next, index += 10) {
417 assert(hop->has_sid);
418 assert(hop->is_mpls);
419
420 segment = srte_segment_entry_add(segment_list, index);
421
422 segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
423 SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
424
425 if (!hop->has_nai)
426 continue;
427 if (srte_segment_entry_set_nai(
428 segment, srte_nai_type(hop->nai.type),
429 &hop->nai.local_addr, hop->nai.local_iface,
430 &hop->nai.remote_addr, hop->nai.remote_iface, 0, 0)
431 == PATH_SID_ERROR)
432 /* TED queries don't match PCE */
433 /* Don't apply srte,zebra changes */
434 number_of_sid_clashed++;
435 }
436
437 candidate->lsp->segment_list = segment_list;
438 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
439
440 for (metric = path->first_metric; metric != NULL; metric = metric->next)
441 srte_lsp_set_metric(
442 candidate->lsp,
443 (enum srte_candidate_metric_type)metric->type,
444 metric->value, metric->enforce, metric->is_bound,
445 metric->is_computed);
446
447 if (path->has_bandwidth)
448 srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
449 path->enforce_bandwidth);
450
451 if (path->has_pce_objfun) {
452 SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
453 candidate->lsp->objfun = path->pce_objfun;
454 }
455
456 if (number_of_sid_clashed)
457 SET_FLAG(segment_list->flags, 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 case SRTE_POLICY_STATUS_DOWN:
494 case SRTE_POLICY_STATUS_UNKNOWN:
495 return PCEP_LSP_OPERATIONAL_DOWN;
496 }
497
498 assert(!"Reached end of function where we are not expecting to");
499 }
500
501 enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
502 {
503 switch (type) {
504 case SRTE_SEGMENT_NAI_TYPE_NONE:
505 return PCEP_SR_SUBOBJ_NAI_ABSENT;
506 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
507 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
508 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
509 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
510 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
511 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
512 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
513 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
514 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
515 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
516 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
517 return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY;
518 case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
519 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
520 case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
521 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
522 case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
523 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
524 case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
525 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
526 default:
527 return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
528 }
529 }
530
531 enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
532 {
533 switch (type) {
534 case PCEP_SR_SUBOBJ_NAI_ABSENT:
535 return SRTE_SEGMENT_NAI_TYPE_NONE;
536 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
537 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
538 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
539 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
540 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
541 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
542 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
543 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
544 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
545 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
546 case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY:
547 case PCEP_SR_SUBOBJ_NAI_UNKNOWN:
548 return SRTE_SEGMENT_NAI_TYPE_NONE;
549 }
550
551 assert(!"Reached end of function where we were not expecting to");
552 }