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