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