]> git.proxmox.com Git - mirror_frr.git/blob - pathd/path_pcep_lib.c
Merge pull request #12708 from donaldsharp/no_notification
[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 default:
771 break;
772 }
773 }
774 if (ero_obj == NULL) {
775 ero_obj = (struct pcep_object_ro_subobj *)
776 pcep_obj_create_ro_subobj_sr_nonai(
777 hop->is_loose, sid,
778 hop->has_attribs, /* C Flag */
779 hop->is_mpls); /* M Flag */
780 }
781 dll_append(ero_objs, ero_obj);
782 }
783 ero = pcep_obj_create_ero(ero_objs);
784 assert(ero != NULL);
785 ero->header.flag_p = true;
786 dll_append(objs, ero);
787
788 if (path->plsp_id == 0) {
789 return objs;
790 }
791
792 pcep_lib_format_constraints(path, objs);
793
794 return objs;
795 }
796
797 void pcep_lib_format_constraints(struct path *path, double_linked_list *objs)
798 {
799 struct pcep_object_metric *metric;
800 struct pcep_object_bandwidth *bandwidth;
801 struct pcep_object_lspa *lspa;
802
803 /* LSPA object */
804 if (path->has_affinity_filters) {
805 lspa = pcep_obj_create_lspa(
806 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1],
807 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1],
808 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1],
809 DEFAULT_LSAP_SETUP_PRIO, DEFAULT_LSAP_HOLDING_PRIO,
810 DEFAULT_LSAP_LOCAL_PRETECTION);
811 assert(lspa != NULL);
812 lspa->header.flag_p = true;
813 dll_append(objs, lspa);
814 }
815
816 /* Bandwidth Objects */
817 if (path->has_bandwidth) {
818 /* Requested Bandwidth */
819 bandwidth = pcep_obj_create_bandwidth(path->bandwidth);
820 assert(bandwidth != NULL);
821 bandwidth->header.flag_p = path->enforce_bandwidth;
822 dll_append(objs, bandwidth);
823 }
824
825 /* Metric Objects */
826 for (struct path_metric *m = path->first_metric; m != NULL;
827 m = m->next) {
828 metric = pcep_obj_create_metric(m->type, m->is_bound,
829 m->is_computed, m->value);
830 assert(metric != NULL);
831 metric->header.flag_p = m->enforce;
832 dll_append(objs, metric);
833 }
834 }
835
836 void pcep_lib_parse_open(struct pcep_caps *caps, struct pcep_object_open *open)
837 {
838 double_linked_list *tlvs = open->header.tlv_list;
839 double_linked_list_node *node;
840 struct pcep_object_tlv_header *tlv_header;
841
842 caps->is_stateful = false;
843 caps->supported_ofs_are_known = false;
844 caps->supported_ofs = 0;
845
846 for (node = tlvs->head; node != NULL; node = node->next_node) {
847 tlv_header = (struct pcep_object_tlv_header *)node->data;
848 switch (tlv_header->type) {
849 case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
850 pcep_lib_parse_open_pce_capability(caps, tlv_header);
851 break;
852 case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
853 break;
854 case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST:
855 pcep_lib_parse_open_objfun_list(caps, tlv_header);
856 break;
857 default:
858 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
859 "Unexpected OPEN's TLV %s (%u)",
860 pcep_tlv_type_name(tlv_header->type),
861 tlv_header->type);
862 break;
863 }
864 }
865 }
866
867 void pcep_lib_parse_open_pce_capability(
868 struct pcep_caps *caps, struct pcep_object_tlv_header *tlv_header)
869 {
870 struct pcep_object_tlv_stateful_pce_capability *tlv;
871 tlv = (struct pcep_object_tlv_stateful_pce_capability *)tlv_header;
872 caps->is_stateful = tlv->flag_u_lsp_update_capability;
873 }
874
875 void pcep_lib_parse_open_objfun_list(struct pcep_caps *caps,
876 struct pcep_object_tlv_header *tlv_header)
877 {
878 double_linked_list_node *node;
879 struct pcep_object_tlv_of_list *tlv;
880 tlv = (struct pcep_object_tlv_of_list *)tlv_header;
881 uint16_t of_code;
882 caps->supported_ofs_are_known = true;
883 for (node = tlv->of_list->head; node != NULL; node = node->next_node) {
884 of_code = *(uint16_t *)node->data;
885 if (of_code >= 32) {
886 zlog_warn(
887 "Ignoring unexpected objective function with code %u",
888 of_code);
889 continue;
890 }
891 SET_FLAG(caps->supported_ofs, of_code);
892 }
893 }
894
895 void pcep_lib_parse_rp(struct path *path, struct pcep_object_rp *rp)
896 {
897 double_linked_list *tlvs = rp->header.tlv_list;
898 double_linked_list_node *node;
899 struct pcep_object_tlv_header *tlv;
900
901 if (tlvs == NULL) {
902 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
903 "Unexpected Empty RP's TLV plsp-id:(%d)",
904 path ? (int32_t)path->plsp_id : -1);
905 return;
906 }
907 /* We ignore the other flags and priority for now */
908 path->req_id = rp->request_id;
909 path->has_pce_objfun = false;
910 path->pce_objfun = OBJFUN_UNDEFINED;
911
912 for (node = tlvs->head; node != NULL; node = node->next_node) {
913 tlv = (struct pcep_object_tlv_header *)node->data;
914 switch (tlv->type) {
915 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
916 // TODO: enforce the path setup type is SR_TE_PST
917 break;
918 default:
919 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
920 "Unexpected RP's TLV %s (%u)",
921 pcep_tlv_type_name(tlv->type), tlv->type);
922 break;
923 }
924 }
925 }
926
927 void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp)
928 {
929 double_linked_list *tlvs = srp->header.tlv_list;
930 double_linked_list_node *node;
931 struct pcep_object_tlv_header *tlv;
932
933 path->do_remove = srp->flag_lsp_remove;
934 path->srp_id = srp->srp_id_number;
935
936 if (tlvs == NULL) {
937 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
938 "Unexpected Empty SRP's TLV plsp-id:(%d)",
939 path ? (int32_t)path->plsp_id : -1);
940 return;
941 }
942 for (node = tlvs->head; node != NULL; node = node->next_node) {
943 tlv = (struct pcep_object_tlv_header *)node->data;
944 switch (tlv->type) {
945 case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE:
946 // TODO: enforce the path setup type is SR_TE_PST
947 break;
948 default:
949 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
950 "Unexpected SRP's TLV %s (%u)",
951 pcep_tlv_type_name(tlv->type), tlv->type);
952 break;
953 }
954 }
955 }
956
957 void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp)
958 {
959 double_linked_list *tlvs = lsp->header.tlv_list;
960 double_linked_list_node *node;
961 struct pcep_object_tlv_header *tlv;
962 struct pcep_object_tlv_symbolic_path_name *name;
963 struct pcep_object_tlv_arbitrary *arb_tlv;
964
965 path->plsp_id = lsp->plsp_id;
966 path->status = lsp->operational_status;
967 path->go_active = lsp->flag_a;
968 path->was_created = lsp->flag_c;
969 path->was_removed = lsp->flag_r;
970 path->is_synching = lsp->flag_s;
971 path->is_delegated = lsp->flag_d;
972
973 if (tlvs == NULL) {
974 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
975 "Unexpected Empty LSP's TLV plsp-id:(%d)",
976 path ? (int32_t)path->plsp_id : -1);
977 return;
978 }
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_SYMBOLIC_PATH_NAME:
984 name = (struct pcep_object_tlv_symbolic_path_name *)tlv;
985 pcep_lib_parse_lsp_symbolic_name(path, name);
986 break;
987 case PCEP_OBJ_TYPE_CISCO_BSID:
988 arb_tlv = (struct pcep_object_tlv_arbitrary *)tlv;
989 memcpy(&path->binding_sid, arb_tlv->data + 2,
990 sizeof(path->binding_sid));
991 path->binding_sid = ntohl(path->binding_sid);
992 path->binding_sid = (path->binding_sid >> 12);
993 break;
994 default:
995 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
996 "Unexpected LSP TLV %s (%u)",
997 pcep_tlv_type_name(tlv->type), tlv->type);
998 break;
999 }
1000 }
1001 }
1002
1003 void pcep_lib_parse_lsp_symbolic_name(
1004 struct path *path, struct pcep_object_tlv_symbolic_path_name *tlv)
1005 {
1006 uint16_t size = tlv->symbolic_path_name_length;
1007 assert(path->name == NULL);
1008 size = size > MAX_PATH_NAME_SIZE ? MAX_PATH_NAME_SIZE : size;
1009 path->name = XCALLOC(MTYPE_PCEP, size);
1010 strlcpy((char *)path->name, tlv->symbolic_path_name, size + 1);
1011 }
1012
1013 void pcep_lib_parse_lspa(struct path *path, struct pcep_object_lspa *lspa)
1014 {
1015 path->has_affinity_filters = true;
1016 path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
1017 lspa->lspa_exclude_any;
1018 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
1019 lspa->lspa_include_any;
1020 path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
1021 lspa->lspa_include_all;
1022 }
1023
1024 void pcep_lib_parse_metric(struct path *path, struct pcep_object_metric *obj)
1025 {
1026 struct path_metric *metric;
1027
1028 metric = pcep_new_metric();
1029 metric->type = obj->type;
1030 metric->is_bound = obj->flag_b;
1031 metric->is_computed = obj->flag_c;
1032 metric->value = obj->value;
1033 metric->next = path->first_metric;
1034 path->first_metric = metric;
1035 }
1036
1037 void pcep_lib_parse_endpoints_ipv4(struct path *path,
1038 struct pcep_object_endpoints_ipv4 *obj)
1039 {
1040 SET_IPADDR_V4(&path->pcc_addr);
1041 path->pcc_addr.ipaddr_v4 = obj->src_ipv4;
1042 SET_IPADDR_V4(&path->nbkey.endpoint);
1043 path->nbkey.endpoint.ipaddr_v4 = obj->dst_ipv4;
1044 }
1045
1046 void pcep_lib_parse_endpoints_ipv6(struct path *path,
1047 struct pcep_object_endpoints_ipv6 *obj)
1048 {
1049 SET_IPADDR_V6(&path->pcc_addr);
1050 path->pcc_addr.ipaddr_v6 = obj->src_ipv6;
1051 SET_IPADDR_V6(&path->nbkey.endpoint);
1052 path->nbkey.endpoint.ipaddr_v6 = obj->dst_ipv6;
1053 }
1054
1055 void pcep_lib_parse_vendor_info(struct path *path,
1056 struct pcep_object_vendor_info *obj)
1057 {
1058 if (obj->enterprise_number == ENTERPRISE_NUMBER_CISCO
1059 && obj->enterprise_specific_info == ENTERPRISE_COLOR_CISCO)
1060 path->nbkey.color = obj->enterprise_specific_info1;
1061 else
1062 path->nbkey.color = 0;
1063 }
1064
1065 void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero)
1066 {
1067 struct path_hop *hop = NULL;
1068 double_linked_list *objs = ero->sub_objects;
1069 double_linked_list_node *node;
1070 struct pcep_object_ro_subobj *obj;
1071
1072 if (objs == NULL) {
1073 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
1074 "Unexpected Empty ERO's sub_obj plsp-id:(%d)",
1075 path ? (int32_t)path->plsp_id : -1);
1076 return;
1077 }
1078 for (node = objs->tail; node != NULL; node = node->prev_node) {
1079 obj = (struct pcep_object_ro_subobj *)node->data;
1080 switch (obj->ro_subobj_type) {
1081 case RO_SUBOBJ_TYPE_SR:
1082 hop = pcep_lib_parse_ero_sr(
1083 hop, (struct pcep_ro_subobj_sr *)obj);
1084 break;
1085 default:
1086 flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_ERO_SUBOBJ,
1087 "Unexpected ERO sub-object %s (%u)",
1088 pcep_ro_type_name(obj->ro_subobj_type),
1089 obj->ro_subobj_type);
1090 break;
1091 }
1092 }
1093
1094 path->first_hop = hop;
1095 }
1096
1097 struct path_hop *pcep_lib_parse_ero_sr(struct path_hop *next,
1098 struct pcep_ro_subobj_sr *sr)
1099 {
1100 struct path_hop *hop = NULL;
1101 union sid sid;
1102
1103 /* Only support IPv4 node with SID */
1104 assert(!sr->flag_s);
1105
1106 if (sr->flag_m) {
1107 sid.mpls = (struct sid_mpls){
1108 .label = GET_SR_ERO_SID_LABEL(sr->sid),
1109 .traffic_class = GET_SR_ERO_SID_TC(sr->sid),
1110 .is_bottom = GET_SR_ERO_SID_S(sr->sid),
1111 .ttl = GET_SR_ERO_SID_TTL(sr->sid)};
1112 } else {
1113 sid.value = sr->sid;
1114 }
1115
1116 hop = pcep_new_hop();
1117 *hop = (struct path_hop){.next = next,
1118 .is_loose =
1119 sr->ro_subobj.flag_subobj_loose_hop,
1120 .has_sid = !sr->flag_s,
1121 .is_mpls = sr->flag_m,
1122 .has_attribs = sr->flag_c,
1123 .sid = sid,
1124 .has_nai = !sr->flag_f,
1125 .nai = {.type = sr->nai_type}};
1126
1127 if (!sr->flag_f) {
1128 assert(sr->nai_list != NULL);
1129 double_linked_list_node *n = sr->nai_list->head;
1130 assert(n != NULL);
1131 assert(n->data != NULL);
1132 switch (sr->nai_type) {
1133 case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
1134 hop->nai.local_addr.ipa_type = IPADDR_V4;
1135 memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
1136 sizeof(struct in_addr));
1137 break;
1138 case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
1139 hop->nai.local_addr.ipa_type = IPADDR_V6;
1140 memcpy(&hop->nai.local_addr.ipaddr_v6, n->data,
1141 sizeof(struct in6_addr));
1142 break;
1143 case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
1144 hop->nai.local_addr.ipa_type = IPADDR_V4;
1145 memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
1146 sizeof(struct in_addr));
1147 n = n->next_node;
1148 assert(n != NULL);
1149 assert(n->data != NULL);
1150 hop->nai.remote_addr.ipa_type = IPADDR_V4;
1151 memcpy(&hop->nai.remote_addr.ipaddr_v4, n->data,
1152 sizeof(struct in_addr));
1153 break;
1154 case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
1155 hop->nai.local_addr.ipa_type = IPADDR_V6;
1156 memcpy(&hop->nai.local_addr.ipaddr_v6, n->data,
1157 sizeof(struct in6_addr));
1158 n = n->next_node;
1159 assert(n != NULL);
1160 assert(n->data != NULL);
1161 hop->nai.remote_addr.ipa_type = IPADDR_V6;
1162 memcpy(&hop->nai.remote_addr.ipaddr_v6, n->data,
1163 sizeof(struct in6_addr));
1164 break;
1165 case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
1166 hop->nai.local_addr.ipa_type = IPADDR_V4;
1167 memcpy(&hop->nai.local_addr.ipaddr_v4, n->data,
1168 sizeof(struct in_addr));
1169 n = n->next_node;
1170 assert(n != NULL);
1171 assert(n->data != NULL);
1172 hop->nai.local_iface = *(uint32_t *)n->data;
1173 n = n->next_node;
1174 assert(n != NULL);
1175 assert(n->data != NULL);
1176 hop->nai.remote_addr.ipa_type = IPADDR_V4;
1177 memcpy(&hop->nai.remote_addr.ipaddr_v4, n->data,
1178 sizeof(struct in_addr));
1179 n = n->next_node;
1180 assert(n != NULL);
1181 assert(n->data != NULL);
1182 hop->nai.remote_iface = *(uint32_t *)n->data;
1183 break;
1184 default:
1185 hop->has_nai = false;
1186 flog_warn(EC_PATH_PCEP_UNEXPECTED_SR_NAI,
1187 "Unexpected SR segment NAI type %s (%u)",
1188 pcep_nai_type_name(sr->nai_type),
1189 sr->nai_type);
1190 break;
1191 }
1192 }
1193
1194 return hop;
1195 }
1196
1197 struct counters_group *copy_counter_group(struct counters_group *from)
1198 {
1199 int size, i;
1200 struct counters_group *result;
1201 if (from == NULL)
1202 return NULL;
1203 assert(from->max_subgroups >= from->num_subgroups);
1204 result = XCALLOC(MTYPE_PCEP, sizeof(*result));
1205 memcpy(result, from, sizeof(*result));
1206 size = sizeof(struct counters_subgroup *) * (from->max_subgroups + 1);
1207 result->subgroups = XCALLOC(MTYPE_PCEP, size);
1208 for (i = 0; i <= from->max_subgroups; i++)
1209 result->subgroups[i] =
1210 copy_counter_subgroup(from->subgroups[i]);
1211 return result;
1212 }
1213
1214 struct counters_subgroup *copy_counter_subgroup(struct counters_subgroup *from)
1215 {
1216 int size, i;
1217 struct counters_subgroup *result;
1218 if (from == NULL)
1219 return NULL;
1220 assert(from->max_counters >= from->num_counters);
1221 result = XCALLOC(MTYPE_PCEP, sizeof(*result));
1222 memcpy(result, from, sizeof(*result));
1223 size = sizeof(struct counter *) * (from->max_counters + 1);
1224 result->counters = XCALLOC(MTYPE_PCEP, size);
1225 for (i = 0; i <= from->max_counters; i++)
1226 result->counters[i] = copy_counter(from->counters[i]);
1227 return result;
1228 }
1229
1230 struct counter *copy_counter(struct counter *from)
1231 {
1232 struct counter *result;
1233 if (from == NULL)
1234 return NULL;
1235 result = XCALLOC(MTYPE_PCEP, sizeof(*result));
1236 memcpy(result, from, sizeof(*result));
1237 return result;
1238 }
1239
1240 void free_counter_group(struct counters_group *group)
1241 {
1242 int i;
1243 if (group == NULL)
1244 return;
1245 for (i = 0; i <= group->max_subgroups; i++)
1246 free_counter_subgroup(group->subgroups[i]);
1247 XFREE(MTYPE_PCEP, group->subgroups);
1248 XFREE(MTYPE_PCEP, group);
1249 }
1250
1251 void free_counter_subgroup(struct counters_subgroup *subgroup)
1252 {
1253 int i;
1254 if (subgroup == NULL)
1255 return;
1256 for (i = 0; i <= subgroup->max_counters; i++)
1257 free_counter(subgroup->counters[i]);
1258 XFREE(MTYPE_PCEP, subgroup->counters);
1259 XFREE(MTYPE_PCEP, subgroup);
1260 }
1261
1262 void free_counter(struct counter *counter)
1263 {
1264 if (counter == NULL)
1265 return;
1266 XFREE(MTYPE_PCEP, counter);
1267 }