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