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