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