]> git.proxmox.com Git - mirror_frr.git/blame - pceplib/pcep_pcc.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / pceplib / pcep_pcc.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: LGPL-2.1-or-later
74971473
JG
2/*
3 * This file is part of the PCEPlib, a PCEP protocol library.
4 *
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
6 *
74971473
JG
7 * Author : Brady Johnson <brady@voltanet.io>
8 *
9 */
10
11
12/*
13 * Sample PCC implementation
14 */
15
16#include <zebra.h>
17
18#include <netdb.h> // gethostbyname
19#include <netinet/tcp.h>
20#include <pthread.h>
21#include <signal.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <time.h>
26#include <unistd.h>
27
28#include "pcep_pcc_api.h"
29#include "pcep_utils_double_linked_list.h"
30#include "pcep_utils_logging.h"
31#include "pcep_utils_memory.h"
32
33/*
34 * PCEP PCC design spec:
35 * https://docs.google.com/presentation/d/1DYc3ZhYA1c_qg9A552HjhneJXQKdh_yrKW6v3NRYPtnbw/edit?usp=sharing
36 */
37#define MAX_SRC_IP_STR 40
38#define MAX_DST_IP_STR 40
39struct cmd_line_args {
40 char src_ip_str[MAX_SRC_IP_STR];
41 char dest_ip_str[MAX_DST_IP_STR];
42 short src_tcp_port;
43 short dest_tcp_port;
2a034138 44 char tcp_md5_str[PCEP_MD5SIG_MAXKEYLEN]; /* RFC 2385 */
74971473
JG
45 bool is_ipv6;
46 bool eventpoll; /* poll for pcep_event's, or use callback (default) */
47};
48
49bool pcc_active_ = true;
50pcep_session *session = NULL;
51struct cmd_line_args *cmd_line_args = NULL;
52/* pcep_event callback variables */
53bool pcep_event_condition = false;
54struct pcep_event *event = NULL;
55pthread_mutex_t pcep_event_mutex;
56pthread_cond_t pcep_event_cond_var;
57
58static const char DEFAULT_DEST_HOSTNAME[] = "localhost";
59static const char DEFAULT_DEST_HOSTNAME_IPV6[] = "ip6-localhost";
60static const short DEFAULT_SRC_TCP_PORT = 4999;
61
62// Private fn's
63struct cmd_line_args *get_cmdline_args(int argc, char *argv[]);
64void handle_signal_action(int sig_number);
74971473
JG
65void send_pce_path_request_message(pcep_session *session);
66void send_pce_report_message(pcep_session *session);
67void print_queue_event(struct pcep_event *event);
68void pcep_event_callback(void *cb_data, pcep_event *e);
69
70struct cmd_line_args *get_cmdline_args(int argc, char *argv[])
71{
72 /* Allocate and set default values */
73 struct cmd_line_args *cmd_line_args =
74 malloc(sizeof(struct cmd_line_args));
75 memset(cmd_line_args, 0, sizeof(struct cmd_line_args));
76 strlcpy(cmd_line_args->dest_ip_str, DEFAULT_DEST_HOSTNAME,
77 MAX_DST_IP_STR);
78 cmd_line_args->src_tcp_port = DEFAULT_SRC_TCP_PORT;
79 cmd_line_args->is_ipv6 = false;
80
81 /* Parse the cmd_line args:
82 * -ipv6
83 * -srcip localhost
84 * -destip 192.168.0.2
85 * -srcport 4999
86 * -dstport 4189
87 * -tcpmd5 hello
88 * -event_poll */
89 int i = 1;
90 for (; i < argc; ++i) {
91 if (strcmp(argv[i], "-help") == 0
92 || strcmp(argv[i], "--help") == 0
93 || strcmp(argv[i], "-h") == 0) {
94 pcep_log(
95 LOG_INFO,
96 "%s: pcep_pcc [-ipv6] [-srcip localhost] [-destip 192.168.0.1] [-srcport 4999] [-dstport 4189] [-tcpmd5 authstr] [-eventpoll]",
97 __func__);
98 free(cmd_line_args);
99 return NULL;
100 } else if (strcmp(argv[i], "-ipv6") == 0) {
101 cmd_line_args->is_ipv6 = true;
102 if (argc == 2) {
103 strlcpy(cmd_line_args->dest_ip_str,
104 DEFAULT_DEST_HOSTNAME_IPV6,
105 MAX_DST_IP_STR);
106 }
107 } else if (strcmp(argv[i], "-eventpoll") == 0) {
108 cmd_line_args->eventpoll = true;
109 } else if (strcmp(argv[i], "-srcip") == 0) {
110 if (argc >= i + 2) {
111 strlcpy(cmd_line_args->src_ip_str, argv[++i],
112 MAX_SRC_IP_STR);
113 } else {
114 pcep_log(
115 LOG_ERR,
116 "%s: Invalid number of cmd_line_args for \"-srcip\"",
117 __func__);
118 free(cmd_line_args);
119 return NULL;
120 }
121 } else if (strcmp(argv[i], "-destip") == 0) {
122 if (argc >= i + 2) {
123 strlcpy(cmd_line_args->dest_ip_str, argv[++i],
124 MAX_DST_IP_STR);
125 } else {
126 pcep_log(
127 LOG_ERR,
128 "%s: Invalid number of cmd_line_args for \"-destip\"",
129 __func__);
130 free(cmd_line_args);
131 return NULL;
132 }
133 } else if (strcmp(argv[i], "-srcport") == 0) {
134 if (argc >= i + 2) {
135 cmd_line_args->src_tcp_port = atoi(argv[++i]);
136 } else {
137 pcep_log(
138 LOG_ERR,
139 "%s: Invalid number of cmd_line_args for \"-srcport\"",
140 __func__);
141 free(cmd_line_args);
142 return NULL;
143 }
144 } else if (strcmp(argv[i], "-destport") == 0) {
145 if (argc >= i + 2) {
146 cmd_line_args->dest_tcp_port = atoi(argv[++i]);
147 } else {
148 pcep_log(
149 LOG_ERR,
150 "%s: Invalid number of cmd_line_args for \"-destport\"",
151 __func__);
152 free(cmd_line_args);
153 return NULL;
154 }
155 } else if (strcmp(argv[i], "-tcpmd5") == 0) {
156 if (argc >= i + 2) {
157 strlcpy(cmd_line_args->tcp_md5_str, argv[++i],
158 sizeof(cmd_line_args->tcp_md5_str));
159 } else {
160 pcep_log(
161 LOG_ERR,
162 "%s: Invalid number of cmd_line_args for \"-tcpmd5\"",
163 __func__);
164 free(cmd_line_args);
165 return NULL;
166 }
167 } else {
168 pcep_log(LOG_ERR, "%s: Invalid cmd_line_arg[%d] = %s",
169 __func__, i, argv[i]);
170 free(cmd_line_args);
171 return NULL;
172 }
173 }
174
175 return cmd_line_args;
176}
177
178void handle_signal_action(int sig_number)
179{
180 if (sig_number == SIGINT) {
181 pcep_log(LOG_INFO, "%s: SIGINT was caught!", __func__);
182 pcc_active_ = false;
183 if (cmd_line_args->eventpoll == false) {
184 pthread_mutex_lock(&pcep_event_mutex);
185 pcep_event_condition = true;
186 pthread_cond_signal(&pcep_event_cond_var);
187 pthread_mutex_unlock(&pcep_event_mutex);
188 }
189 } else if (sig_number == SIGUSR1) {
190 pcep_log(LOG_INFO, "%s: SIGUSR1 was caught, dumping counters",
191 __func__);
192 dump_pcep_session_counters(session);
193 pceplib_memory_dump();
194 } else if (sig_number == SIGUSR2) {
195 pcep_log(LOG_INFO, "%s: SIGUSR2 was caught, reseting counters",
196 __func__);
197 reset_pcep_session_counters(session);
198 }
199}
200
2816045a 201static int setup_signals(void)
74971473
JG
202{
203 struct sigaction sa;
6006b807 204 memset(&sa, 0, sizeof(sa));
74971473
JG
205 sa.sa_handler = handle_signal_action;
206 if (sigaction(SIGINT, &sa, 0) != 0) {
207 perror("sigaction()");
208 return -1;
209 }
210
211 if (sigaction(SIGUSR1, &sa, 0) != 0) {
212 perror("sigaction()");
213 return -1;
214 }
215
216 if (sigaction(SIGUSR2, &sa, 0) != 0) {
217 perror("sigaction()");
218 return -1;
219 }
220
221 return 0;
222}
223
224void send_pce_path_request_message(pcep_session *session)
225{
226 struct in_addr src_ipv4;
227 struct in_addr dst_ipv4;
228 inet_pton(AF_INET, "1.2.3.4", &src_ipv4);
229 inet_pton(AF_INET, "10.20.30.40", &dst_ipv4);
230
231 struct pcep_object_rp *rp_object =
232 pcep_obj_create_rp(1, false, false, false, false, 42, NULL);
233 struct pcep_object_endpoints_ipv4 *ep_object =
234 pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4);
235
236 struct pcep_message *path_request =
237 pcep_msg_create_request(rp_object, ep_object, NULL);
238 send_message(session, path_request, true);
239}
240
241void send_pce_report_message(pcep_session *session)
242{
243 double_linked_list *report_list = dll_initialize();
244
245 /* SRP Path Setup Type TLV */
246 struct pcep_object_tlv_path_setup_type *pst_tlv =
247 pcep_tlv_create_path_setup_type(SR_TE_PST);
248 double_linked_list *srp_tlv_list = dll_initialize();
249 dll_append(srp_tlv_list, pst_tlv);
250
251 /*
252 * Create the SRP object
253 */
254 uint32_t srp_id_number = 0x10203040;
255 struct pcep_object_header *obj =
256 (struct pcep_object_header *)pcep_obj_create_srp(
257 false, srp_id_number, srp_tlv_list);
258 if (obj == NULL) {
259 pcep_log(LOG_WARNING,
260 "%s: send_pce_report_message SRP object was NULL",
261 __func__);
b8cc7b62 262 dll_destroy_with_data(report_list);
74971473
JG
263 return;
264 }
265 dll_append(report_list, obj);
266
267 /* LSP Symbolic path name TLV */
268 char symbolic_path_name[] = "second-default";
269 struct pcep_object_tlv_symbolic_path_name *spn_tlv =
270 pcep_tlv_create_symbolic_path_name(symbolic_path_name, 14);
271 double_linked_list *lsp_tlv_list = dll_initialize();
272 dll_append(lsp_tlv_list, spn_tlv);
273
274 /* LSP IPv4 LSP ID TLV */
275 struct in_addr ipv4_tunnel_sender;
276 struct in_addr ipv4_tunnel_endpoint;
277 inet_pton(AF_INET, "9.9.1.1", &ipv4_tunnel_sender);
278 inet_pton(AF_INET, "9.9.2.1", &ipv4_tunnel_endpoint);
279 struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id_tlv =
280 pcep_tlv_create_ipv4_lsp_identifiers(&ipv4_tunnel_sender,
281 &ipv4_tunnel_endpoint, 42,
282 1, NULL);
283 dll_append(lsp_tlv_list, ipv4_lsp_id_tlv);
284
285 /*
286 * Create the LSP object
287 */
288 uint32_t plsp_id = 42;
289 enum pcep_lsp_operational_status lsp_status =
290 PCEP_LSP_OPERATIONAL_ACTIVE;
291 bool c_flag = false; /* Lsp was created by PcInitiate msg */
292 bool a_flag = false; /* Admin state, active / inactive */
293 bool r_flag = false; /* true if LSP has been removed */
294 bool s_flag = true; /* Synchronization */
295 bool d_flag = false; /* Delegate LSP to PCE */
296 obj = (struct pcep_object_header *)pcep_obj_create_lsp(
297 plsp_id, lsp_status, c_flag, a_flag, r_flag, s_flag, d_flag,
298 lsp_tlv_list);
299 if (obj == NULL) {
300 pcep_log(LOG_WARNING,
301 "%s: send_pce_report_message LSP object was NULL",
302 __func__);
b8cc7b62 303 dll_destroy_with_data(report_list);
74971473
JG
304 return;
305 }
306 dll_append(report_list, obj);
307
308 /* Create 2 ERO NONAI sub-objects */
309 double_linked_list *ero_subobj_list = dll_initialize();
310 struct pcep_ro_subobj_sr *sr_subobj_nonai1 =
311 pcep_obj_create_ro_subobj_sr_nonai(false, 503808, true, true);
312 dll_append(ero_subobj_list, sr_subobj_nonai1);
313
314 struct pcep_ro_subobj_sr *sr_subobj_nonai2 =
315 pcep_obj_create_ro_subobj_sr_nonai(false, 1867776, true, true);
316 dll_append(ero_subobj_list, sr_subobj_nonai2);
317
318 /* Create ERO IPv4 node sub-object */
319 struct in_addr sr_subobj_ipv4;
320 inet_pton(AF_INET, "9.9.9.1", &sr_subobj_ipv4);
321 struct pcep_ro_subobj_sr *sr_subobj_ipv4node =
322 pcep_obj_create_ro_subobj_sr_ipv4_node(
323 false, false, false, true, 16060, &sr_subobj_ipv4);
324 if (sr_subobj_ipv4node == NULL) {
325 pcep_log(LOG_WARNING,
326 "%s: send_pce_report_message ERO sub-object was NULL",
327 __func__);
328 return;
329 }
330 dll_append(ero_subobj_list, sr_subobj_ipv4node);
331
332 /*
333 * Create the ERO object
334 */
335 obj = (struct pcep_object_header *)pcep_obj_create_ero(ero_subobj_list);
336 if (obj == NULL) {
337 pcep_log(LOG_WARNING,
338 "%s: send_pce_report_message ERO object was NULL",
339 __func__);
b8cc7b62 340 dll_destroy_with_data(report_list);
74971473
JG
341 return;
342 }
343 dll_append(report_list, obj);
344
345 /*
346 * Create the Metric object
347 */
348 obj = (struct pcep_object_header *)pcep_obj_create_metric(
349 PCEP_METRIC_TE, false, true, 16.0);
350 dll_append(report_list, obj);
351
352 /* Create and send the report message */
353 struct pcep_message *report_msg = pcep_msg_create_report(report_list);
354 send_message(session, report_msg, true);
355}
356
357void print_queue_event(struct pcep_event *event)
358{
359 pcep_log(
360 LOG_INFO,
361 "%s: [%ld-%ld] Received Event: type [%s] on session [%d] occurred at [%ld]",
362 __func__, time(NULL), pthread_self(),
363 get_event_type_str(event->event_type),
364 event->session->session_id, event->event_time);
365
366 if (event->event_type == MESSAGE_RECEIVED) {
367 pcep_log(
368 LOG_INFO, "%s: \t Event message type [%s]", __func__,
369 get_message_type_str(event->message->msg_header->type));
370 }
371}
372
373/* Called by pcep_session_logic when pcep_event's are ready */
374void pcep_event_callback(void *cb_data, pcep_event *e)
375{
376 (void)cb_data;
377 pcep_log(LOG_NOTICE, "%s: [%ld-%ld] pcep_event_callback", __func__,
378 time(NULL), pthread_self());
379 pthread_mutex_lock(&pcep_event_mutex);
380 event = e;
381 pcep_event_condition = true;
382 pthread_cond_signal(&pcep_event_cond_var);
383 pthread_mutex_unlock(&pcep_event_mutex);
384}
385
386int main(int argc, char **argv)
387{
388 pcep_log(LOG_NOTICE, "%s: [%ld-%ld] starting pcc_pcep example client",
389 __func__, time(NULL), pthread_self());
390
391 cmd_line_args = get_cmdline_args(argc, argv);
392 if (cmd_line_args == NULL) {
393 return -1;
394 }
395
396 setup_signals();
397
398 if (cmd_line_args->eventpoll == false) {
399 struct pceplib_infra_config infra_config;
400 memset(&infra_config, 0, sizeof(infra_config));
401 infra_config.pcep_event_func = pcep_event_callback;
402 if (!initialize_pcc_infra(&infra_config)) {
403 pcep_log(LOG_ERR,
404 "%s: Error initializing PCC with infra.",
405 __func__);
406 return -1;
407 }
408 } else {
409 if (!initialize_pcc()) {
410 pcep_log(LOG_ERR, "%s: Error initializing PCC.",
411 __func__);
412 return -1;
413 }
414 }
415
416 pcep_configuration *config = create_default_pcep_configuration();
417 config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true;
418 config->src_pcep_port = cmd_line_args->src_tcp_port;
419 config->is_tcp_auth_md5 = true;
420
421 strlcpy(config->tcp_authentication_str, cmd_line_args->tcp_md5_str,
422 sizeof(config->tcp_authentication_str));
423
424 int af = (cmd_line_args->is_ipv6 ? AF_INET6 : AF_INET);
425 struct hostent *host_info =
426 gethostbyname2(cmd_line_args->dest_ip_str, af);
427 if (host_info == NULL) {
428 pcep_log(LOG_ERR, "%s: Error getting IP address.", __func__);
429 return -1;
430 }
431
432 if (cmd_line_args->is_ipv6) {
433 struct in6_addr host_address;
434 memcpy(&host_address, host_info->h_addr, host_info->h_length);
435 session = connect_pce_ipv6(config, &host_address);
436 } else {
437 struct in_addr host_address;
438 memcpy(&host_address, host_info->h_addr, host_info->h_length);
439 session = connect_pce(config, &host_address);
440 }
441
442 if (session == NULL) {
443 pcep_log(LOG_WARNING, "%s: Error in connect_pce.", __func__);
444 destroy_pcep_configuration(config);
445 return -1;
446 }
447
448 sleep(2);
449
450 send_pce_report_message(session);
451 /*send_pce_path_request_message(session);*/
452
453 /* Wait for pcep_event's either by polling the event queue or by
454 * callback */
455 if (cmd_line_args->eventpoll == true) {
456 /* Poll the pcep_event queue*/
457 while (pcc_active_) {
458 if (event_queue_is_empty() == false) {
459 struct pcep_event *event =
460 event_queue_get_event();
461 print_queue_event(event);
462 destroy_pcep_event(event);
463 }
464
465 sleep(5);
466 }
467 } else {
468 /* Get events via callback and conditional variable */
469 pthread_mutex_init(&pcep_event_mutex, NULL);
470 pthread_cond_init(&pcep_event_cond_var, NULL);
471 while (pcc_active_) {
472 pthread_mutex_lock(&pcep_event_mutex);
473
474 /* this internal loop helps avoid spurious interrupts */
475 while (!pcep_event_condition) {
476 pthread_cond_wait(&pcep_event_cond_var,
477 &pcep_event_mutex);
478 }
479
480 /* Check if we have been interrupted by SIGINT */
481 if (pcc_active_) {
482 print_queue_event(event);
483 destroy_pcep_event(event);
484 }
485
486 pcep_event_condition = false;
487 pthread_mutex_unlock(&pcep_event_mutex);
488 }
489
490 pthread_mutex_destroy(&pcep_event_mutex);
491 pthread_cond_destroy(&pcep_event_cond_var);
492 }
493
494 pcep_log(LOG_NOTICE, "%s: Disconnecting from PCE", __func__);
495 disconnect_pce(session);
496 destroy_pcep_configuration(config);
497 free(cmd_line_args);
498
499 if (!destroy_pcc()) {
500 pcep_log(LOG_NOTICE, "%s: Error stopping PCC.", __func__);
501 }
502
503 pceplib_memory_dump();
504
505 return 0;
506}