]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_lib.c
Merge pull request #8305 from donaldsharp/bgp_ll_ifp_change
[mirror_frr.git] / pathd / path_pcep_lib.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 "memory.h"
22
23 #include <debug.h>
24 #include "pceplib/pcep_utils_counters.h"
25 #include "pceplib/pcep_timers.h"
26 #include "pathd/path_errors.h"
27 #include "pathd/path_pcep.h"
28 #include "pathd/path_pcep_lib.h"
29 #include "pathd/path_pcep_debug.h"
30
31 DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure");
32 DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages");
33
34 #define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
35 #define DEFAULT_LSAP_SETUP_PRIO 4
36 #define DEFAULT_LSAP_HOLDING_PRIO 4
37 #define DEFAULT_LSAP_LOCAL_PRETECTION false
38
39 /* pceplib logging callback */
40 static int pceplib_logging_cb(int level, const char *fmt, va_list args);
41
42 /* Socket callbacks */
43 static int pcep_lib_pceplib_socket_read_cb(void *fpt, void **thread, int fd,
44 void *payload);
45 static int pcep_lib_pceplib_socket_write_cb(void *fpt, void **thread, int fd,
46 void *payload);
47 static int pcep_lib_socket_read_ready(struct thread *thread);
48 static int pcep_lib_socket_write_ready(struct thread *thread);
49
50 /* pceplib pcep_event callbacks */
51 static void pcep_lib_pceplib_event_cb(void *fpt, pcep_event *event);
52
53 /* pceplib pthread creation callback */
54 static int pcep_lib_pthread_create_cb(pthread_t *pthread_id,
55 const pthread_attr_t *attr,
56 void *(*start_routine)(void *),
57 void *data, const char *thread_name);
58 void *pcep_lib_pthread_start_passthrough(void *data);
59 int pcep_lib_pthread_stop_cb(struct frr_pthread *, void **);
60
61 /* Internal functions */
62 static double_linked_list *pcep_lib_format_path(struct pcep_caps *caps,
63 struct path *path);
64 static void pcep_lib_format_constraints(struct path *path,
65 double_linked_list *objs);
66 static void pcep_lib_parse_open(struct pcep_caps *caps,
67 struct pcep_object_open *open);
68 static void
69 pcep_lib_parse_open_pce_capability(struct pcep_caps *caps,
70 struct pcep_object_tlv_header *tlv_header);
71 static void
72 pcep_lib_parse_open_objfun_list(struct pcep_caps *caps,
73 struct pcep_object_tlv_header *tlv_header);
74 static void pcep_lib_parse_rp(struct path *path, struct pcep_object_rp *rp);
75 static void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp);
76 static void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp);
77 static void pcep_lib_parse_lspa(struct path *path,
78 struct pcep_object_lspa *lspa);
79 static void pcep_lib_parse_metric(struct path *path,
80 struct pcep_object_metric *obj);
81 static void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero);
82 static struct path_hop *pcep_lib_parse_ero_sr(struct path_hop *next,
83 struct pcep_ro_subobj_sr *sr);
84 static struct counters_group *copy_counter_group(struct counters_group *from);
85 static struct counters_subgroup *
86 copy_counter_subgroup(struct counters_subgroup *from);
87 static struct counter *copy_counter(struct counter *from);
88 static void free_counter_group(struct counters_group *group);
89 static void free_counter_subgroup(struct counters_subgroup *subgroup);
90 static void free_counter(struct counter *counter);
91
92 struct pcep_lib_pthread_passthrough_data {
93 void *(*start_routine)(void *data);
94 void *data;
95 };
96
97 /* ------------ API Functions ------------ */
98
99 int pcep_lib_initialize(struct frr_pthread *fpt)
100 {
101 PCEP_DEBUG("Initializing pceplib");
102
103 /* Register pceplib logging callback */
104 register_logger(pceplib_logging_cb);
105
106 /* Its ok that this object goes out of scope, as it
107 * wont be stored, and its values will be copied */
108 struct pceplib_infra_config infra = {
109 /* Memory infrastructure */
110 .pceplib_infra_mt = MTYPE_PCEPLIB_INFRA,
111 .pceplib_messages_mt = MTYPE_PCEPLIB_MESSAGES,
112 .malloc_func = (pceplib_malloc_func)qmalloc,
113 .calloc_func = (pceplib_calloc_func)qcalloc,
114 .realloc_func = (pceplib_realloc_func)qrealloc,
115 .strdup_func = (pceplib_strdup_func)qstrdup,
116 .free_func = (pceplib_free_func)qfree,
117 /* Timers infrastructure */
118 .external_infra_data = fpt,
119 .socket_read_func = pcep_lib_pceplib_socket_read_cb,
120 .socket_write_func = pcep_lib_pceplib_socket_write_cb,
121 /* PCEP events */
122 .pcep_event_func = pcep_lib_pceplib_event_cb,
123 /* PCEPlib pthread creation callback */
124 .pthread_create_func = pcep_lib_pthread_create_cb};
125 if (!initialize_pcc_infra(&infra)) {
126 flog_err(EC_PATH_PCEP_PCC_INIT, "failed to initialize pceplib");
127 return 1;
128 }
129
130 return 0;
131 }
132
133 void pcep_lib_finalize(void)
134 {
135 PCEP_DEBUG("Finalizing pceplib");
136 if (!destroy_pcc()) {
137 flog_err(EC_PATH_PCEP_PCC_FINI, "failed to finalize pceplib");
138 }
139 }
140
141
142 pcep_session *
143 pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr,
144 int dst_port, short msd,
145 const struct pcep_config_group_opts *pcep_options)
146 {
147 pcep_configuration *config;
148 pcep_session *sess;
149
150 config = create_default_pcep_configuration();
151 config->dst_pcep_port = dst_port;
152 config->src_pcep_port = src_port;
153 if (IS_IPADDR_V6(src_addr)) {
154 config->is_src_ipv6 = true;
155 memcpy(&config->src_ip.src_ipv6, &src_addr->ipaddr_v6,
156 sizeof(struct in6_addr));
157 } else {
158 config->is_src_ipv6 = false;
159 config->src_ip.src_ipv4 = src_addr->ipaddr_v4;
160 }
161
162 config->support_stateful_pce_lsp_update = true;
163 config->support_pce_lsp_instantiation = false;
164 config->support_include_db_version = false;
165 config->support_lsp_triggered_resync = false;
166 config->support_lsp_delta_sync = false;
167 config->support_pce_triggered_initial_sync = false;
168 config->support_sr_te_pst = true;
169 config->pcc_can_resolve_nai_to_sid = false;
170
171 config->max_sid_depth = msd;
172 config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 =
173 pcep_options->draft07;
174 config->keep_alive_seconds = pcep_options->keep_alive_seconds;
175 config->min_keep_alive_seconds = pcep_options->min_keep_alive_seconds;
176 config->max_keep_alive_seconds = pcep_options->max_keep_alive_seconds;
177 config->dead_timer_seconds = pcep_options->dead_timer_seconds;
178 config->min_dead_timer_seconds = pcep_options->min_dead_timer_seconds;
179 config->max_dead_timer_seconds = pcep_options->max_dead_timer_seconds;
180 config->request_time_seconds = pcep_options->pcep_request_time_seconds;
181 /* TODO when available in the pceplib, set it here
182 pcep_options->state_timeout_inteval_seconds;*/
183
184 if (pcep_options->tcp_md5_auth[0] != '\0') {
185 config->is_tcp_auth_md5 = true;
186 strlcpy(config->tcp_authentication_str,
187 pcep_options->tcp_md5_auth,
188 sizeof(config->tcp_authentication_str));
189 } else {
190 config->is_tcp_auth_md5 = false;
191 }
192
193 if (IS_IPADDR_V6(dst_addr)) {
194 sess = connect_pce_ipv6(config, &dst_addr->ipaddr_v6);
195 } else {
196 sess = connect_pce(config, &dst_addr->ipaddr_v4);
197 }
198 destroy_pcep_configuration(config);
199 return sess;
200 }
201
202 void pcep_lib_disconnect(pcep_session *sess)
203 {
204 assert(sess != NULL);
205 disconnect_pce(sess);
206 }
207
208 /* Callback passed to pceplib to write to a socket.
209 * When the socket is ready to be written to,
210 * pcep_lib_socket_write_ready() will be called */
211
212 int pcep_lib_pceplib_socket_write_cb(void *fpt, void **thread, int fd,
213 void *payload)
214 {
215 return pcep_thread_socket_write(fpt, thread, fd, payload,
216 pcep_lib_socket_write_ready);
217 }
218
219 /* Callback passed to pceplib to read from a socket.
220 * When the socket is ready to be read from,
221 * pcep_lib_socket_read_ready() will be called */
222
223 int pcep_lib_pceplib_socket_read_cb(void *fpt, void **thread, int fd,
224 void *payload)
225 {
226 return pcep_thread_socket_read(fpt, thread, fd, payload,
227 pcep_lib_socket_read_ready);
228 }
229
230 /* Callbacks called by path_pcep_controller when a socket is ready to read/write
231 */
232
233 int pcep_lib_socket_write_ready(struct thread *thread)
234 {
235 struct pcep_ctrl_socket_data *data = THREAD_ARG(thread);
236 assert(data != NULL);
237
238 int retval = pceplib_external_socket_write(data->fd, data->payload);
239 XFREE(MTYPE_PCEP, data);
240
241 return retval;
242 }
243
244 int pcep_lib_socket_read_ready(struct thread *thread)
245 {
246 struct pcep_ctrl_socket_data *data = THREAD_ARG(thread);
247 assert(data != NULL);
248
249 int retval = pceplib_external_socket_read(data->fd, data->payload);
250 XFREE(MTYPE_PCEP, data);
251
252 return retval;
253 }
254
255 /* Callback passed to pceplib when a pcep_event is ready */
256 void pcep_lib_pceplib_event_cb(void *fpt, pcep_event *event)
257 {
258 pcep_thread_send_ctrl_event(fpt, event, pcep_thread_pcep_event);
259 }
260
261 /* Wrapper function around the actual pceplib thread start function */
262 void *pcep_lib_pthread_start_passthrough(void *data)
263 {
264 struct frr_pthread *fpt = data;
265 struct pcep_lib_pthread_passthrough_data *passthrough_data = fpt->data;
266 void *start_routine_data = passthrough_data->data;
267 void *(*start_routine)(void *) = passthrough_data->start_routine;
268 XFREE(MTYPE_PCEP, passthrough_data);
269
270 if (start_routine != NULL) {
271 return start_routine(start_routine_data);
272 }
273
274 return NULL;
275 }
276
277 int pcep_lib_pthread_create_cb(pthread_t *thread_id, const pthread_attr_t *attr,
278 void *(*start_routine)(void *), void *data,
279 const char *thread_name)
280 {
281 /* Since FRR calls the start_routine with a struct frr_pthread,
282 * we have to store the real data and callback in a passthrough
283 * and pass the actual data the start_routine needs */
284 struct pcep_lib_pthread_passthrough_data *passthrough_data = XMALLOC(
285 MTYPE_PCEP, sizeof(struct pcep_lib_pthread_passthrough_data));
286 passthrough_data->data = data;
287 passthrough_data->start_routine = start_routine;
288
289 struct frr_pthread_attr fpt_attr = {
290 .start = pcep_lib_pthread_start_passthrough,
291 .stop = pcep_lib_pthread_stop_cb};
292 struct frr_pthread *fpt =
293 frr_pthread_new(&fpt_attr, thread_name, "pcep_lib");
294 if (fpt == NULL) {
295 return 1;
296 }
297
298 fpt->data = passthrough_data;
299 int retval = frr_pthread_run(fpt, attr);
300 if (retval) {
301 return retval;
302 }
303
304 *thread_id = fpt->thread;
305
306 return 0;
307 }
308
309 int pcep_lib_pthread_stop_cb(struct frr_pthread *fpt, void **res)
310 {
311 pcep_lib_finalize();
312 frr_pthread_destroy(fpt);
313
314 return 0;
315 }
316
317 struct pcep_message *pcep_lib_format_report(struct pcep_caps *caps,
318 struct path *path)
319 {
320 double_linked_list *objs = pcep_lib_format_path(caps, path);
321 return pcep_msg_create_report(objs);
322 }
323
324 static struct pcep_object_rp *create_rp(uint32_t reqid)
325 {
326 double_linked_list *rp_tlvs;
327 struct pcep_object_tlv_path_setup_type *setup_type_tlv;
328 struct pcep_object_rp *rp;
329
330 rp_tlvs = dll_initialize();
331 setup_type_tlv = pcep_tlv_create_path_setup_type(SR_TE_PST);
332 dll_append(rp_tlvs, setup_type_tlv);
333
334 rp = pcep_obj_create_rp(0, false, false, false, true, reqid, rp_tlvs);
335
336 return rp;
337 }
338
339 struct pcep_message *pcep_lib_format_request(struct pcep_caps *caps,
340 struct path *path)
341 {
342 struct ipaddr *src = &path->pcc_addr;
343 struct ipaddr *dst = &path->nbkey.endpoint;
344 double_linked_list *objs;
345 struct pcep_object_rp *rp;
346 struct pcep_object_endpoints_ipv4 *endpoints_ipv4;
347 struct pcep_object_endpoints_ipv6 *endpoints_ipv6;
348 struct pcep_object_objective_function *of = NULL;
349 enum objfun_type objfun = OBJFUN_UNDEFINED;
350
351 assert(src->ipa_type == dst->ipa_type);
352
353 objs = dll_initialize();
354 rp = create_rp(path->req_id);
355 rp->header.flag_p = true;
356
357 pcep_lib_format_constraints(path, objs);
358
359 /* Objective Function */
360 if (path->has_pcc_objfun) {
361 objfun = path->pcc_objfun;
362 }
363
364 if (objfun != OBJFUN_UNDEFINED) {
365 of = pcep_obj_create_objective_function(objfun, NULL);
366 assert(of != NULL);
367 of->header.flag_p = path->enforce_pcc_objfun;
368 dll_append(objs, of);
369 }
370
371 if (IS_IPADDR_V6(src)) {
372 endpoints_ipv6 = pcep_obj_create_endpoint_ipv6(&src->ipaddr_v6,
373 &dst->ipaddr_v6);
374 endpoints_ipv6->header.flag_p = true;
375 return pcep_msg_create_request_ipv6(rp, endpoints_ipv6, objs);
376 } else {
377 endpoints_ipv4 = pcep_obj_create_endpoint_ipv4(&src->ipaddr_v4,
378 &dst->ipaddr_v4);
379 endpoints_ipv4->header.flag_p = true;
380 return pcep_msg_create_request(rp, endpoints_ipv4, objs);
381 }
382 }
383
384 struct pcep_message *pcep_lib_format_error(int error_type, int error_value)
385 {
386 return pcep_msg_create_error(error_type, error_value);
387 }
388
389 struct pcep_message *pcep_lib_format_request_cancelled(uint32_t reqid)
390 {
391 struct pcep_object_notify *notify;
392 double_linked_list *objs;
393 struct pcep_object_rp *rp;
394
395 notify = pcep_obj_create_notify(
396 PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED,
397 PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST);
398 objs = dll_initialize();
399 rp = create_rp(reqid);
400 dll_append(objs, rp);
401
402 return pcep_msg_create_notify(notify, objs);
403 }
404
405 struct path *pcep_lib_parse_path(struct pcep_message *msg)
406 {
407 struct path *path;
408 double_linked_list *objs = msg->obj_list;
409 double_linked_list_node *node;
410
411 struct pcep_object_header *obj;
412 struct pcep_object_rp *rp = NULL;
413 struct pcep_object_srp *srp = NULL;
414 struct pcep_object_lsp *lsp = NULL;
415 struct pcep_object_lspa *lspa = NULL;
416 struct pcep_object_ro *ero = NULL;
417 struct pcep_object_metric *metric = NULL;
418 struct pcep_object_bandwidth *bandwidth = NULL;
419 struct pcep_object_objective_function *of = NULL;
420
421 path = pcep_new_path();
422
423 for (node = objs->head; node != NULL; node = node->next_node) {
424 obj = (struct pcep_object_header *)node->data;
425 switch (CLASS_TYPE(obj->object_class, obj->object_type)) {
426 case CLASS_TYPE(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP):
427 assert(rp == NULL);
428 rp = (struct pcep_object_rp *)obj;
429 pcep_lib_parse_rp(path, rp);
430 break;
431 case CLASS_TYPE(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP):
432 assert(srp == NULL);
433 srp = (struct pcep_object_srp *)obj;
434 pcep_lib_parse_srp(path, srp);
435 break;
436 case CLASS_TYPE(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP):
437 /* Only support single LSP per message */
438 assert(lsp == NULL);
439 lsp = (struct pcep_object_lsp *)obj;
440 pcep_lib_parse_lsp(path, lsp);
441 break;
442 case CLASS_TYPE(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA):
443 assert(lspa == NULL);
444 lspa = (struct pcep_object_lspa *)obj;
445 pcep_lib_parse_lspa(path, lspa);
446 break;
447 case CLASS_TYPE(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO):
448 /* Only support single ERO per message */
449 assert(ero == NULL);
450 ero = (struct pcep_object_ro *)obj;
451 pcep_lib_parse_ero(path, ero);
452 break;
453 case CLASS_TYPE(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC):
454 metric = (struct pcep_object_metric *)obj;
455 pcep_lib_parse_metric(path, metric);
456 break;
457 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH,
458 PCEP_OBJ_TYPE_BANDWIDTH_REQ):
459 case CLASS_TYPE(PCEP_OBJ_CLASS_BANDWIDTH,
460 PCEP_OBJ_TYPE_BANDWIDTH_CISCO):
461 bandwidth = (struct pcep_object_bandwidth *)obj;
462 path->has_bandwidth = true;
463 path->bandwidth = bandwidth->bandwidth;
464 break;
465 case CLASS_TYPE(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH):
466 path->no_path = true;
467 break;
468 case CLASS_TYPE(PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF):
469 of = (struct pcep_object_objective_function *)obj;
470 path->has_pce_objfun = true;
471 path->pce_objfun = of->of_code;
472 break;
473 default:
474 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
475 "Unexpected PCEP object %s (%u) / %s (%u)",
476 pcep_object_class_name(obj->object_class),
477 obj->object_class,
478 pcep_object_type_name(obj->object_class,
479 obj->object_type),
480 obj->object_type);
481 break;
482 }
483 }
484
485 return path;
486 }
487
488 void pcep_lib_parse_capabilities(struct pcep_message *msg,
489 struct pcep_caps *caps)
490 {
491 double_linked_list *objs = msg->obj_list;
492 double_linked_list_node *node;
493
494 struct pcep_object_header *obj;
495 struct pcep_object_open *open = NULL;
496
497 for (node = objs->head; node != NULL; node = node->next_node) {
498 obj = (struct pcep_object_header *)node->data;
499 switch (CLASS_TYPE(obj->object_class, obj->object_type)) {
500 case CLASS_TYPE(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN):
501 assert(open == NULL);
502 open = (struct pcep_object_open *)obj;
503 pcep_lib_parse_open(caps, open);
504 break;
505 default:
506 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
507 "Unexpected PCEP object %s (%u) / %s (%u)",
508 pcep_object_class_name(obj->object_class),
509 obj->object_class,
510 pcep_object_type_name(obj->object_class,
511 obj->object_type),
512 obj->object_type);
513 break;
514 }
515 }
516 }
517
518 struct counters_group *pcep_lib_copy_counters(pcep_session *sess)
519 {
520 if (!sess || !sess->pcep_session_counters) {
521 return NULL;
522 }
523
524 return copy_counter_group(sess->pcep_session_counters);
525 }
526
527 void pcep_lib_free_counters(struct counters_group *counters)
528 {
529 free_counter_group(counters);
530 }
531
532 pcep_session *pcep_lib_copy_pcep_session(pcep_session *sess)
533 {
534 if (!sess) {
535 return NULL;
536 }
537
538 pcep_session *copy;
539 copy = XCALLOC(MTYPE_PCEP, sizeof(*copy));
540 memcpy(copy, sess, sizeof(*copy));
541 /* These fields should not be accessed */
542 copy->num_unknown_messages_time_queue = NULL;
543 copy->socket_comm_session = NULL;
544 copy->pcep_session_counters = NULL;
545
546 return copy;
547 }
548
549 /* ------------ pceplib logging callback ------------ */
550
551 int pceplib_logging_cb(int priority, const char *fmt, va_list args)
552 {
553 char buffer[1024];
554 vsnprintf(buffer, sizeof(buffer), fmt, args);
555 PCEP_DEBUG_PCEPLIB(priority, "pceplib: %s", buffer);
556 return 0;
557 }
558
559 /* ------------ Internal Functions ------------ */
560
561 double_linked_list *pcep_lib_format_path(struct pcep_caps *caps,
562 struct path *path)
563 {
564 struct in_addr addr_null;
565 double_linked_list *objs, *srp_tlvs, *lsp_tlvs, *ero_objs;
566 struct pcep_object_tlv_header *tlv;
567 struct pcep_object_ro_subobj *ero_obj;
568 struct pcep_object_srp *srp;
569 struct pcep_object_lsp *lsp;
570 struct pcep_object_ro *ero;
571 uint32_t encoded_binding_sid;
572 char binding_sid_lsp_tlv_data[6];
573
574 memset(&addr_null, 0, sizeof(addr_null));
575
576 objs = dll_initialize();
577
578 if (path->plsp_id != 0) {
579 /* SRP object */
580 srp_tlvs = dll_initialize();
581 tlv = (struct pcep_object_tlv_header *)
582 pcep_tlv_create_path_setup_type(SR_TE_PST);
583 assert(tlv != NULL);
584 dll_append(srp_tlvs, tlv);
585 srp = pcep_obj_create_srp(path->do_remove, path->srp_id,
586 srp_tlvs);
587 assert(srp != NULL);
588 srp->header.flag_p = true;
589 dll_append(objs, srp);
590 }
591
592 /* LSP object */
593 lsp_tlvs = dll_initialize();
594
595 if (path->plsp_id == 0 || IS_IPADDR_NONE(&path->nbkey.endpoint)
596 || IS_IPADDR_NONE(&path->pcc_addr)) {
597 tlv = (struct pcep_object_tlv_header *)
598 pcep_tlv_create_ipv4_lsp_identifiers(
599 &addr_null, &addr_null, 0, 0, &addr_null);
600 } else {
601 assert(path->pcc_addr.ipa_type
602 == path->nbkey.endpoint.ipa_type);
603 if (IS_IPADDR_V4(&path->pcc_addr)) {
604 tlv = (struct pcep_object_tlv_header *)
605 pcep_tlv_create_ipv4_lsp_identifiers(
606 &path->pcc_addr.ipaddr_v4,
607 &path->nbkey.endpoint.ipaddr_v4, 0, 0,
608 &path->pcc_addr.ipaddr_v4);
609 } else {
610 tlv = (struct pcep_object_tlv_header *)
611 pcep_tlv_create_ipv6_lsp_identifiers(
612 &path->pcc_addr.ipaddr_v6,
613 &path->nbkey.endpoint.ipaddr_v6, 0, 0,
614 &path->pcc_addr.ipaddr_v6);
615 }
616 }
617 assert(tlv != NULL);
618 dll_append(lsp_tlvs, tlv);
619 if (path->name != NULL) {
620 tlv = (struct pcep_object_tlv_header *)
621 /*FIXME: Remove the typecasty when pceplib is changed
622 to take a const char* */
623 pcep_tlv_create_symbolic_path_name((char *)path->name,
624 strlen(path->name));
625 assert(tlv != NULL);
626 dll_append(lsp_tlvs, tlv);
627 }
628 if ((path->plsp_id != 0) && (path->binding_sid != MPLS_LABEL_NONE)) {
629 memset(binding_sid_lsp_tlv_data, 0, 2);
630 encoded_binding_sid = htonl(path->binding_sid << 12);
631 memcpy(binding_sid_lsp_tlv_data + 2, &encoded_binding_sid, 4);
632 tlv = (struct pcep_object_tlv_header *)
633 pcep_tlv_create_tlv_arbitrary(
634 binding_sid_lsp_tlv_data,
635 sizeof(binding_sid_lsp_tlv_data), 65505);
636 assert(tlv != NULL);
637 dll_append(lsp_tlvs, tlv);
638 }
639 lsp = pcep_obj_create_lsp(
640 path->plsp_id, path->status, path->was_created /* C Flag */,
641 path->go_active /* A Flag */, path->was_removed /* R Flag */,
642 path->is_synching /* S Flag */, path->is_delegated /* D Flag */,
643 lsp_tlvs);
644 assert(lsp != NULL);
645 lsp->header.flag_p = true;
646 dll_append(objs, lsp);
647 /* ERO object */
648 ero_objs = dll_initialize();
649 for (struct path_hop *hop = path->first_hop; hop != NULL;
650 hop = hop->next) {
651 uint32_t sid;
652
653 /* Only supporting MPLS hops with both sid and nai */
654 assert(hop->is_mpls);
655 assert(hop->has_sid);
656
657 if (hop->has_attribs) {
658 sid = ENCODE_SR_ERO_SID(hop->sid.mpls.label,
659 hop->sid.mpls.traffic_class,
660 hop->sid.mpls.is_bottom,
661 hop->sid.mpls.ttl);
662 } else {
663 sid = ENCODE_SR_ERO_SID(hop->sid.mpls.label, 0, 0, 0);
664 }
665
666 ero_obj = NULL;
667 if (hop->has_nai) {
668 assert(hop->nai.type != PCEP_SR_SUBOBJ_NAI_ABSENT);
669 assert(hop->nai.type
670 != PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY);
671 assert(hop->nai.type != PCEP_SR_SUBOBJ_NAI_UNKNOWN);
672 switch (hop->nai.type) {
673 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
674 ero_obj = (struct pcep_object_ro_subobj *)
675 pcep_obj_create_ro_subobj_sr_ipv4_node(
676 hop->is_loose, !hop->has_sid,
677 hop->has_attribs, /* C Flag */
678 hop->is_mpls, /* M Flag */
679 sid,
680 &hop->nai.local_addr.ipaddr_v4);
681 break;
682 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
683 ero_obj = (struct pcep_object_ro_subobj *)
684 pcep_obj_create_ro_subobj_sr_ipv6_node(
685 hop->is_loose, !hop->has_sid,
686 hop->has_attribs, /* C Flag */
687 hop->is_mpls, /* M Flag */
688 sid,
689 &hop->nai.local_addr.ipaddr_v6);
690 break;
691 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
692 ero_obj = (struct pcep_object_ro_subobj *)
693 pcep_obj_create_ro_subobj_sr_ipv4_adj(
694 hop->is_loose, !hop->has_sid,
695 hop->has_attribs, /* C Flag */
696 hop->is_mpls, /* M Flag */
697 sid,
698 &hop->nai.local_addr.ipaddr_v4,
699 &hop->nai.remote_addr
700 .ipaddr_v4);
701 break;
702 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
703 ero_obj = (struct pcep_object_ro_subobj *)
704 pcep_obj_create_ro_subobj_sr_ipv6_adj(
705 hop->is_loose, !hop->has_sid,
706 hop->has_attribs, /* C Flag */
707 hop->is_mpls, /* M Flag */
708 sid,
709 &hop->nai.local_addr.ipaddr_v6,
710 &hop->nai.remote_addr
711 .ipaddr_v6);
712 break;
713 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
714 ero_obj = (struct pcep_object_ro_subobj *)
715 pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
716 hop->is_loose, !hop->has_sid,
717 hop->has_attribs, /* C Flag */
718 hop->is_mpls, /* M Flag */
719 sid,
720 hop->nai.local_addr.ipaddr_v4
721 .s_addr,
722 hop->nai.local_iface,
723 hop->nai.remote_addr.ipaddr_v4
724 .s_addr,
725 hop->nai.remote_iface);
726 break;
727 default:
728 break;
729 }
730 }
731 if (ero_obj == NULL) {
732 ero_obj = (struct pcep_object_ro_subobj *)
733 pcep_obj_create_ro_subobj_sr_nonai(
734 hop->is_loose, sid,
735 hop->has_attribs, /* C Flag */
736 hop->is_mpls); /* M Flag */
737 }
738 dll_append(ero_objs, ero_obj);
739 }
740 ero = pcep_obj_create_ero(ero_objs);
741 assert(ero != NULL);
742 ero->header.flag_p = true;
743 dll_append(objs, ero);
744
745 if (path->plsp_id == 0) {
746 return objs;
747 }
748
749 pcep_lib_format_constraints(path, objs);
750
751 return objs;
752 }
753
754 void pcep_lib_format_constraints(struct path *path, double_linked_list *objs)
755 {
756 struct pcep_object_metric *metric;
757 struct pcep_object_bandwidth *bandwidth;
758 struct pcep_object_lspa *lspa;
759
760 /* LSPA object */
761 if (path->has_affinity_filters) {
762 lspa = pcep_obj_create_lspa(
763 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1],
764 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1],
765 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1],
766 DEFAULT_LSAP_SETUP_PRIO, DEFAULT_LSAP_HOLDING_PRIO,
767 DEFAULT_LSAP_LOCAL_PRETECTION);
768 assert(lspa != NULL);
769 lspa->header.flag_p = true;
770 dll_append(objs, lspa);
771 }
772
773 /* Bandwidth Objects */
774 if (path->has_bandwidth) {
775 /* Requested Bandwidth */
776 bandwidth = pcep_obj_create_bandwidth(path->bandwidth);
777 assert(bandwidth != NULL);
778 bandwidth->header.flag_p = path->enforce_bandwidth;
779 dll_append(objs, bandwidth);
780 }
781
782 /* Metric Objects */
783 for (struct path_metric *m = path->first_metric; m != NULL;
784 m = m->next) {
785 metric = pcep_obj_create_metric(m->type, m->is_bound,
786 m->is_computed, m->value);
787 assert(metric != NULL);
788 metric->header.flag_p = m->enforce;
789 dll_append(objs, metric);
790 }
791 }
792
793 void pcep_lib_parse_open(struct pcep_caps *caps, struct pcep_object_open *open)
794 {
795 double_linked_list *tlvs = open->header.tlv_list;
796 double_linked_list_node *node;
797 struct pcep_object_tlv_header *tlv_header;
798
799 caps->is_stateful = false;
800 caps->supported_ofs_are_known = false;
801 caps->supported_ofs = 0;
802
803 for (node = tlvs->head; node != NULL; node = node->next_node) {
804 tlv_header = (struct pcep_object_tlv_header *)node->data;
805 switch (tlv_header->type) {
806 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
807 pcep_lib_parse_open_pce_capability(caps, tlv_header);
808 break;
809 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
810 break;
811 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST:
812 pcep_lib_parse_open_objfun_list(caps, tlv_header);
813 break;
814 default:
815 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
816 "Unexpected OPEN's TLV %s (%u)",
817 pcep_tlv_type_name(tlv_header->type),
818 tlv_header->type);
819 break;
820 }
821 }
822 }
823
824 void pcep_lib_parse_open_pce_capability(
825 struct pcep_caps *caps, struct pcep_object_tlv_header *tlv_header)
826 {
827 struct pcep_object_tlv_stateful_pce_capability *tlv;
828 tlv = (struct pcep_object_tlv_stateful_pce_capability *)tlv_header;
829 caps->is_stateful = tlv->flag_u_lsp_update_capability;
830 }
831
832 void pcep_lib_parse_open_objfun_list(struct pcep_caps *caps,
833 struct pcep_object_tlv_header *tlv_header)
834 {
835 double_linked_list_node *node;
836 struct pcep_object_tlv_of_list *tlv;
837 tlv = (struct pcep_object_tlv_of_list *)tlv_header;
838 uint16_t of_code;
839 caps->supported_ofs_are_known = true;
840 for (node = tlv->of_list->head; node != NULL; node = node->next_node) {
841 of_code = *(uint16_t *)node->data;
842 if (of_code >= 32) {
843 zlog_warn(
844 "Ignoring unexpected objective function with code %u",
845 of_code);
846 continue;
847 }
848 SET_FLAG(caps->supported_ofs, of_code);
849 }
850 }
851
852 void pcep_lib_parse_rp(struct path *path, struct pcep_object_rp *rp)
853 {
854 double_linked_list *tlvs = rp->header.tlv_list;
855 double_linked_list_node *node;
856 struct pcep_object_tlv_header *tlv;
857
858 /* We ignore the other flags and priority for now */
859 path->req_id = rp->request_id;
860 path->has_pce_objfun = false;
861 path->pce_objfun = OBJFUN_UNDEFINED;
862
863 for (node = tlvs->head; node != NULL; node = node->next_node) {
864 tlv = (struct pcep_object_tlv_header *)node->data;
865 switch (tlv->type) {
866 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
867 // TODO: enforce the path setup type is SR_TE_PST
868 break;
869 default:
870 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
871 "Unexpected RP's TLV %s (%u)",
872 pcep_tlv_type_name(tlv->type), tlv->type);
873 break;
874 }
875 }
876 }
877
878 void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp)
879 {
880 double_linked_list *tlvs = srp->header.tlv_list;
881 double_linked_list_node *node;
882 struct pcep_object_tlv_header *tlv;
883
884 path->do_remove = srp->flag_lsp_remove;
885 path->srp_id = srp->srp_id_number;
886
887 for (node = tlvs->head; node != NULL; node = node->next_node) {
888 tlv = (struct pcep_object_tlv_header *)node->data;
889 switch (tlv->type) {
890 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
891 // TODO: enforce the path setup type is SR_TE_PST
892 break;
893 default:
894 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
895 "Unexpected SRP's TLV %s (%u)",
896 pcep_tlv_type_name(tlv->type), tlv->type);
897 break;
898 }
899 }
900 }
901
902 void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp)
903 {
904 double_linked_list *tlvs = lsp->header.tlv_list;
905 double_linked_list_node *node;
906 struct pcep_object_tlv_header *tlv;
907
908 path->plsp_id = lsp->plsp_id;
909 path->status = lsp->operational_status;
910 path->go_active = lsp->flag_a;
911 path->was_created = lsp->flag_c;
912 path->was_removed = lsp->flag_r;
913 path->is_synching = lsp->flag_s;
914 path->is_delegated = lsp->flag_d;
915
916 if (tlvs == NULL)
917 return;
918
919 for (node = tlvs->head; node != NULL; node = node->next_node) {
920 tlv = (struct pcep_object_tlv_header *)node->data;
921 switch (tlv->type) {
922 default:
923 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
924 "Unexpected LSP TLV %s (%u)",
925 pcep_tlv_type_name(tlv->type), tlv->type);
926 break;
927 }
928 }
929 }
930
931 void pcep_lib_parse_lspa(struct path *path, struct pcep_object_lspa *lspa)
932 {
933 path->has_affinity_filters = true;
934 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
935 lspa->lspa_exclude_any;
936 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
937 lspa->lspa_include_any;
938 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
939 lspa->lspa_include_all;
940 }
941
942 void pcep_lib_parse_metric(struct path *path, struct pcep_object_metric *obj)
943 {
944 struct path_metric *metric;
945
946 metric = pcep_new_metric();
947 metric->type = obj->type;
948 metric->is_bound = obj->flag_b;
949 metric->is_computed = obj->flag_c;
950 metric->value = obj->value;
951 metric->next = path->first_metric;
952 path->first_metric = metric;
953 }
954
955 void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero)
956 {
957 struct path_hop *hop = NULL;
958 double_linked_list *objs = ero->sub_objects;
959 double_linked_list_node *node;
960 struct pcep_object_ro_subobj *obj;
961
962 for (node = objs->tail; node != NULL; node = node->prev_node) {
963 obj = (struct pcep_object_ro_subobj *)node->data;
964 switch (obj->ro_subobj_type) {
965 case RO_SUBOBJ_TYPE_SR:
966 hop = pcep_lib_parse_ero_sr(
967 hop, (struct pcep_ro_subobj_sr *)obj);
968 break;
969 default:
970 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
971 "Unexpected ERO sub-object %s (%u)",
972 pcep_ro_type_name(obj->ro_subobj_type),
973 obj->ro_subobj_type);
974 break;
975 }
976 }
977
978 path->first_hop = hop;
979 }
980
981 struct path_hop *pcep_lib_parse_ero_sr(struct path_hop *next,
982 struct pcep_ro_subobj_sr *sr)
983 {
984 struct path_hop *hop = NULL;
985 union sid sid;
986
987 /* Only support IPv4 node with SID */
988 assert(!sr->flag_s);
989
990 if (sr->flag_m) {
991 sid.mpls = (struct sid_mpls){
992 .label = GET_SR_ERO_SID_LABEL(sr->sid),
993 .traffic_class = GET_SR_ERO_SID_TC(sr->sid),
994 .is_bottom = GET_SR_ERO_SID_S(sr->sid),
995 .ttl = GET_SR_ERO_SID_TTL(sr->sid)};
996 } else {
997 sid.value = sr->sid;
998 }
999
1000 hop = pcep_new_hop();
1001 *hop = (struct path_hop){.next = next,
1002 .is_loose =
1003 sr->ro_subobj.flag_subobj_loose_hop,
1004 .has_sid = !sr->flag_s,
1005 .is_mpls = sr->flag_m,
1006 .has_attribs = sr->flag_c,
1007 .sid = sid,
1008 .has_nai = !sr->flag_f,
1009 .nai = {.type = sr->nai_type}};
1010
1011 if (!sr->flag_f) {
1012 assert(sr->nai_list != NULL);
1013 double_linked_list_node *n = sr->nai_list->head;
1014 assert(n != NULL);
1015 assert(n->data != NULL);
1016 switch (sr->nai_type) {
1017 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
1018 hop->nai.local_addr.ipa_type = IPADDR_V4;
1019 memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
1020 sizeof(struct in_addr));
1021 break;
1022 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
1023 hop->nai.local_addr.ipa_type = IPADDR_V6;
1024 memcpy(&hop->nai.local_addr.ipaddr_v6, n->data,
1025 sizeof(struct in6_addr));
1026 break;
1027 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
1028 hop->nai.local_addr.ipa_type = IPADDR_V4;
1029 memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
1030 sizeof(struct in_addr));
1031 n = n->next_node;
1032 assert(n != NULL);
1033 assert(n->data != NULL);
1034 hop->nai.remote_addr.ipa_type = IPADDR_V4;
1035 memcpy(&hop->nai.remote_addr.ipaddr_v4, n->data,
1036 sizeof(struct in_addr));
1037 break;
1038 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
1039 hop->nai.local_addr.ipa_type = IPADDR_V6;
1040 memcpy(&hop->nai.local_addr.ipaddr_v6, n->data,
1041 sizeof(struct in6_addr));
1042 n = n->next_node;
1043 assert(n != NULL);
1044 assert(n->data != NULL);
1045 hop->nai.remote_addr.ipa_type = IPADDR_V6;
1046 memcpy(&hop->nai.remote_addr.ipaddr_v6, n->data,
1047 sizeof(struct in6_addr));
1048 break;
1049 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
1050 hop->nai.local_addr.ipa_type = IPADDR_V4;
1051 memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
1052 sizeof(struct in_addr));
1053 n = n->next_node;
1054 assert(n != NULL);
1055 assert(n->data != NULL);
1056 hop->nai.local_iface = *(uint32_t *)n->data;
1057 n = n->next_node;
1058 assert(n != NULL);
1059 assert(n->data != NULL);
1060 hop->nai.remote_addr.ipa_type = IPADDR_V4;
1061 memcpy(&hop->nai.remote_addr.ipaddr_v4, n->data,
1062 sizeof(struct in_addr));
1063 n = n->next_node;
1064 assert(n != NULL);
1065 assert(n->data != NULL);
1066 hop->nai.remote_iface = *(uint32_t *)n->data;
1067 break;
1068 default:
1069 hop->has_nai = false;
1070 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI,
1071 "Unexpected SR segment NAI type %s (%u)",
1072 pcep_nai_type_name(sr->nai_type),
1073 sr->nai_type);
1074 break;
1075 }
1076 }
1077
1078 return hop;
1079 }
1080
1081 struct counters_group *copy_counter_group(struct counters_group *from)
1082 {
1083 int size, i;
1084 struct counters_group *result;
1085 if (from == NULL)
1086 return NULL;
1087 assert(from->max_subgroups >= from->num_subgroups);
1088 result = XCALLOC(MTYPE_PCEP, sizeof(*result));
1089 memcpy(result, from, sizeof(*result));
1090 size = sizeof(struct counters_subgroup *) * (from->max_subgroups + 1);
1091 result->subgroups = XCALLOC(MTYPE_PCEP, size);
1092 for (i = 0; i <= from->max_subgroups; i++)
1093 result->subgroups[i] =
1094 copy_counter_subgroup(from->subgroups[i]);
1095 return result;
1096 }
1097
1098 struct counters_subgroup *copy_counter_subgroup(struct counters_subgroup *from)
1099 {
1100 int size, i;
1101 struct counters_subgroup *result;
1102 if (from == NULL)
1103 return NULL;
1104 assert(from->max_counters >= from->num_counters);
1105 result = XCALLOC(MTYPE_PCEP, sizeof(*result));
1106 memcpy(result, from, sizeof(*result));
1107 size = sizeof(struct counter *) * (from->max_counters + 1);
1108 result->counters = XCALLOC(MTYPE_PCEP, size);
1109 for (i = 0; i <= from->max_counters; i++)
1110 result->counters[i] = copy_counter(from->counters[i]);
1111 return result;
1112 }
1113
1114 struct counter *copy_counter(struct counter *from)
1115 {
1116 struct counter *result;
1117 if (from == NULL)
1118 return NULL;
1119 result = XCALLOC(MTYPE_PCEP, sizeof(*result));
1120 memcpy(result, from, sizeof(*result));
1121 return result;
1122 }
1123
1124 void free_counter_group(struct counters_group *group)
1125 {
1126 int i;
1127 if (group == NULL)
1128 return;
1129 for (i = 0; i <= group->max_subgroups; i++)
1130 free_counter_subgroup(group->subgroups[i]);
1131 XFREE(MTYPE_PCEP, group->subgroups);
1132 XFREE(MTYPE_PCEP, group);
1133 }
1134
1135 void free_counter_subgroup(struct counters_subgroup *subgroup)
1136 {
1137 int i;
1138 if (subgroup == NULL)
1139 return;
1140 for (i = 0; i <= subgroup->max_counters; i++)
1141 free_counter(subgroup->counters[i]);
1142 XFREE(MTYPE_PCEP, subgroup->counters);
1143 XFREE(MTYPE_PCEP, subgroup);
1144 }
1145
1146 void free_counter(struct counter *counter)
1147 {
1148 if (counter == NULL)
1149 return;
1150 XFREE(MTYPE_PCEP, counter);
1151 }