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