]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_config.c
pceplib: Integrate pcelib into frr
[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 <northbound.h>
20 #include <yang.h>
21 #include <printfrr.h>
22 #include "pceplib/pcep_msg_objects.h"
23 #include "pathd/pathd.h"
24 #include "pathd/path_pcep.h"
25 #include "pathd/path_pcep_config.h"
26 #include "pathd/path_pcep_debug.h"
27 #include "thread.h"
28
29 #define MAX_XPATH 256
30 #define MAX_FLOAT_LEN 22
31 #define INETADDR4_MAXLEN 16
32 #define INETADDR6_MAXLEN 40
33
34
35 static void copy_candidate_objfun_info(struct srte_candidate *candidate,
36 struct path *path);
37 static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
38 struct path *path);
39 static struct path_hop *
40 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
41 static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
42 static char *candidate_name(struct srte_candidate *candidate);
43 static enum pcep_lsp_operational_status
44 status_int_to_ext(enum srte_policy_status status);
45 static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
46 static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
47
48 void path_pcep_refine_path(struct path *path)
49 {
50 struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
51 struct srte_lsp *lsp;
52
53 if (candidate == NULL)
54 return;
55
56 lsp = candidate->lsp;
57
58 if (path->name == NULL)
59 path->name = candidate_name(candidate);
60 if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
61 path->type = candidate->type;
62 if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
63 path->create_origin = candidate->protocol_origin;
64 if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
65 && (lsp->segment_list != NULL))
66 path->update_origin = lsp->segment_list->protocol_origin;
67 }
68
69 struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
70 {
71 struct srte_candidate *candidate = lookup_candidate(key);
72 if (candidate == NULL)
73 return NULL;
74 return candidate_to_path(candidate);
75 }
76
77 void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
78 {
79 struct path *path;
80 struct srte_policy *policy;
81 struct srte_candidate *candidate;
82
83 RB_FOREACH (policy, srte_policy_head, &srte_policies) {
84 RB_FOREACH (candidate, srte_candidate_head,
85 &policy->candidate_paths) {
86 path = candidate_to_path(candidate);
87 if (!cb(path, arg))
88 return;
89 }
90 }
91 }
92
93 struct path *candidate_to_path(struct srte_candidate *candidate)
94 {
95 char *name;
96 struct path *path;
97 struct path_hop *hop = NULL;
98 struct path_metric *metric = NULL;
99 struct srte_policy *policy;
100 struct srte_lsp *lsp;
101 enum pcep_lsp_operational_status status;
102 enum srte_protocol_origin update_origin = 0;
103 char *originator = NULL;
104
105 policy = candidate->policy;
106 lsp = candidate->lsp;
107
108 if (lsp->segment_list != NULL) {
109 hop = path_pcep_config_list_path_hops(lsp->segment_list);
110 update_origin = lsp->segment_list->protocol_origin;
111 originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
112 }
113 path = pcep_new_path();
114 name = candidate_name(candidate);
115 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
116 status = status_int_to_ext(policy->status);
117 } else {
118 status = PCEP_LSP_OPERATIONAL_DOWN;
119 }
120 for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
121 struct path_metric *path_metric;
122 struct srte_metric *srte_metric = &lsp->metrics[i];
123 if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
124 path_metric = pcep_new_metric();
125 path_metric->next = metric;
126 metric = path_metric;
127 metric->type = i + 1;
128 metric->value = srte_metric->value;
129 metric->enforce = CHECK_FLAG(srte_metric->flags,
130 F_METRIC_IS_REQUIRED);
131 metric->is_bound = CHECK_FLAG(srte_metric->flags,
132 F_METRIC_IS_BOUND);
133 metric->is_computed = CHECK_FLAG(srte_metric->flags,
134 F_METRIC_IS_COMPUTED);
135 }
136 }
137 *path = (struct path){
138 .nbkey = (struct lsp_nb_key){.color = policy->color,
139 .endpoint = policy->endpoint,
140 .preference =
141 candidate->preference},
142 .create_origin = lsp->protocol_origin,
143 .update_origin = update_origin,
144 .originator = originator,
145 .plsp_id = 0,
146 .name = name,
147 .type = candidate->type,
148 .srp_id = 0,
149 .req_id = 0,
150 .binding_sid = policy->binding_sid,
151 .status = status,
152 .do_remove = false,
153 .go_active = false,
154 .was_created = false,
155 .was_removed = false,
156 .is_synching = false,
157 .is_delegated = false,
158 .first_hop = hop,
159 .first_metric = metric};
160
161 path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
162 if (path->has_bandwidth) {
163 path->enforce_bandwidth =
164 CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
165 path->bandwidth = lsp->bandwidth;
166 } else {
167 path->enforce_bandwidth = true;
168 path->bandwidth = 0;
169 }
170
171 copy_candidate_objfun_info(candidate, path);
172 copy_candidate_affinity_filters(candidate, path);
173
174 return path;
175 }
176
177 void copy_candidate_objfun_info(struct srte_candidate *candidate,
178 struct path *path)
179 {
180 struct srte_lsp *lsp = candidate->lsp;
181
182 if (lsp != NULL) {
183 if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
184 path->has_pce_objfun = true;
185 path->pce_objfun = lsp->objfun;
186 } else {
187 path->has_pce_objfun = false;
188 path->pce_objfun = OBJFUN_UNDEFINED;
189 }
190 }
191 if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
192 path->has_pcc_objfun = true;
193 path->pcc_objfun = candidate->objfun;
194 path->enforce_pcc_objfun = CHECK_FLAG(
195 candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
196
197 } else {
198 path->has_pcc_objfun = false;
199 path->pcc_objfun = OBJFUN_UNDEFINED;
200 UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
201 }
202 }
203
204 void copy_candidate_affinity_filters(struct srte_candidate *candidate,
205 struct path *path)
206 {
207 bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
208 bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
209 bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
210 path->has_affinity_filters = eany || iany || iall;
211 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
212 eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
213 - 1]
214 : 0;
215 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
216 iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
217 - 1]
218 : 0;
219 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
220 iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
221 - 1]
222 : 0;
223 }
224
225 struct path_hop *
226 path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
227 {
228 struct srte_segment_entry *segment;
229 struct path_hop *hop = NULL, *last_hop = NULL;
230
231 RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
232 &segment_list->segments) {
233 hop = pcep_new_hop();
234 *hop = (struct path_hop){
235 .next = last_hop,
236 .is_loose = false,
237 .has_sid = true,
238 .is_mpls = true,
239 .has_attribs = false,
240 .sid = {.mpls = {.label = segment->sid_value}},
241 .has_nai =
242 segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
243 .nai = {.type = pcep_nai_type(segment->nai_type)}};
244 switch (segment->nai_type) {
245 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
246 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
247 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
248 sizeof(struct ipaddr));
249 break;
250 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
251 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
252 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
253 sizeof(struct ipaddr));
254 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
255 sizeof(struct ipaddr));
256 break;
257 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
258 memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
259 sizeof(struct ipaddr));
260 hop->nai.local_iface = segment->nai_local_iface;
261 memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
262 sizeof(struct ipaddr));
263 hop->nai.remote_iface = segment->nai_remote_iface;
264 break;
265 default:
266 break;
267 }
268 last_hop = hop;
269 }
270 return hop;
271 }
272
273 int path_pcep_config_update_path(struct path *path)
274 {
275 assert(path != NULL);
276 assert(path->nbkey.preference != 0);
277 assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
278
279 struct path_hop *hop;
280 struct path_metric *metric;
281 int index;
282 char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
283 char *segment_list_name = NULL;
284 struct srte_candidate *candidate;
285 struct srte_segment_list *segment_list = NULL;
286 struct srte_segment_entry *segment;
287
288 candidate = lookup_candidate(&path->nbkey);
289
290 // if there is no candidate to update we are done
291 if (!candidate)
292 return 0;
293
294 // first clean up old segment list if present
295 if (candidate->lsp->segment_list) {
296 SET_FLAG(candidate->lsp->segment_list->flags,
297 F_SEGMENT_LIST_DELETED);
298 candidate->lsp->segment_list = NULL;
299 }
300
301 if (path->first_hop != NULL) {
302 snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
303 "%s-%u", path->name, path->plsp_id);
304 segment_list_name = segment_list_name_buff;
305
306 segment_list = srte_segment_list_add(segment_list_name);
307 segment_list->protocol_origin = path->update_origin;
308 strlcpy(segment_list->originator, path->originator,
309 sizeof(segment_list->originator));
310 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
311 SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
312
313 for (hop = path->first_hop, index = 10; hop != NULL;
314 hop = hop->next, index += 10) {
315 assert(hop->has_sid);
316 assert(hop->is_mpls);
317
318 segment = srte_segment_entry_add(segment_list, index);
319
320 segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
321 SET_FLAG(segment->segment_list->flags,
322 F_SEGMENT_LIST_MODIFIED);
323
324 if (hop->has_nai)
325 srte_segment_entry_set_nai(
326 segment, srte_nai_type(hop->nai.type),
327 &hop->nai.local_addr,
328 hop->nai.local_iface,
329 &hop->nai.remote_addr,
330 hop->nai.remote_iface);
331 }
332 }
333
334 candidate->lsp->segment_list = segment_list;
335 SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
336
337 for (metric = path->first_metric; metric != NULL; metric = metric->next)
338 srte_lsp_set_metric(
339 candidate->lsp,
340 (enum srte_candidate_metric_type)metric->type,
341 metric->value, metric->enforce, metric->is_bound,
342 metric->is_computed);
343
344 if (path->has_bandwidth)
345 srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
346 path->enforce_bandwidth);
347
348 if (path->has_pce_objfun) {
349 SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
350 candidate->lsp->objfun = path->pce_objfun;
351 }
352
353 srte_apply_changes();
354
355 return 0;
356 }
357
358 struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
359 {
360 struct srte_policy *policy = NULL;
361 policy = srte_policy_find(key->color, &key->endpoint);
362 if (policy == NULL)
363 return NULL;
364 return srte_candidate_find(policy, key->preference);
365 }
366
367 char *candidate_name(struct srte_candidate *candidate)
368 {
369 return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
370 candidate->name);
371 }
372
373 enum pcep_lsp_operational_status
374 status_int_to_ext(enum srte_policy_status status)
375 {
376 switch (status) {
377 case SRTE_POLICY_STATUS_UP:
378 return PCEP_LSP_OPERATIONAL_ACTIVE;
379 case SRTE_POLICY_STATUS_GOING_UP:
380 return PCEP_LSP_OPERATIONAL_GOING_UP;
381 case SRTE_POLICY_STATUS_GOING_DOWN:
382 return PCEP_LSP_OPERATIONAL_GOING_DOWN;
383 default:
384 return PCEP_LSP_OPERATIONAL_DOWN;
385 }
386 }
387
388 enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
389 {
390 switch (type) {
391 case SRTE_SEGMENT_NAI_TYPE_NONE:
392 return PCEP_SR_SUBOBJ_NAI_ABSENT;
393 case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
394 return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
395 case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
396 return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
397 case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
398 return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
399 case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
400 return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
401 case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
402 return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
403 default:
404 return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
405 }
406 }
407
408 enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
409 {
410 switch (type) {
411 case PCEP_SR_SUBOBJ_NAI_ABSENT:
412 return SRTE_SEGMENT_NAI_TYPE_NONE;
413 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
414 return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
415 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
416 return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
417 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
418 return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
419 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
420 return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
421 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
422 return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
423 default:
424 return SRTE_SEGMENT_NAI_TYPE_NONE;
425 }
426 }