1 // SPDX-License-Identifier: LGPL-2.1-or-later
3 * This file is part of the PCEPlib, a PCEP protocol library.
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
7 * Author : Brady Johnson <brady@voltanet.io>
13 * Public PCEPlib PCC API implementation
23 #include "pcep_msg_messages.h"
24 #include "pcep_pcc_api.h"
25 #include "pcep_utils_counters.h"
26 #include "pcep_utils_logging.h"
28 /* Not using an array here since the enum pcep_event_type indeces go into the
30 const char MESSAGE_RECEIVED_STR
[] = "MESSAGE_RECEIVED";
31 const char PCE_CLOSED_SOCKET_STR
[] = "PCE_CLOSED_SOCKET";
32 const char PCE_SENT_PCEP_CLOSE_STR
[] = "PCE_SENT_PCEP_CLOSE";
33 const char PCE_DEAD_TIMER_EXPIRED_STR
[] = "PCE_DEAD_TIMER_EXPIRED";
34 const char PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR
[] =
35 "PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED";
36 const char PCC_CONNECTED_TO_PCE_STR
[] = "PCC_CONNECTED_TO_PCE";
37 const char PCC_PCEP_SESSION_CLOSED_STR
[] = "PCC_PCEP_SESSION_CLOSED";
38 const char PCC_RCVD_INVALID_OPEN_STR
[] = "PCC_RCVD_INVALID_OPEN";
39 const char PCC_RCVD_MAX_INVALID_MSGS_STR
[] = "PCC_RCVD_MAX_INVALID_MSGS";
40 const char PCC_RCVD_MAX_UNKOWN_MSGS_STR
[] = "PCC_RCVD_MAX_UNKOWN_MSGS";
41 const char UNKNOWN_EVENT_STR
[] = "UNKNOWN Event Type";
43 /* Session Logic Handle managed in pcep_session_logic.c */
44 extern pcep_event_queue
*session_logic_event_queue_
;
46 bool initialize_pcc(void)
48 if (!run_session_logic()) {
49 pcep_log(LOG_ERR
, "%s: Error initializing PCC session logic.",
58 bool initialize_pcc_infra(struct pceplib_infra_config
*infra_config
)
60 if (infra_config
== NULL
) {
61 return initialize_pcc();
64 if (!run_session_logic_with_infra(infra_config
)) {
66 "%s: Error initializing PCC session logic with infra.",
75 /* this function is blocking */
76 bool initialize_pcc_wait_for_completion(void)
78 return run_session_logic_wait_for_completion();
82 bool destroy_pcc(void)
84 if (!stop_session_logic()) {
85 pcep_log(LOG_WARNING
, "%s: Error stopping PCC session logic.",
94 pcep_configuration
*create_default_pcep_configuration(void)
96 pcep_configuration
*config
=
97 pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_configuration
));
98 memset(config
, 0, sizeof(pcep_configuration
));
100 config
->keep_alive_seconds
= DEFAULT_CONFIG_KEEP_ALIVE
;
101 /* This value will possibly be overwritten later with PCE config data */
102 config
->keep_alive_pce_negotiated_timer_seconds
=
103 DEFAULT_CONFIG_KEEP_ALIVE
;
104 config
->min_keep_alive_seconds
= DEFAULT_MIN_CONFIG_KEEP_ALIVE
;
105 config
->max_keep_alive_seconds
= DEFAULT_MAX_CONFIG_KEEP_ALIVE
;
107 config
->dead_timer_seconds
= DEFAULT_CONFIG_DEAD_TIMER
;
108 /* This value will be overwritten later with PCE config data */
109 config
->dead_timer_pce_negotiated_seconds
= DEFAULT_CONFIG_DEAD_TIMER
;
110 config
->min_dead_timer_seconds
= DEFAULT_MIN_CONFIG_DEAD_TIMER
;
111 config
->max_dead_timer_seconds
= DEFAULT_MAX_CONFIG_DEAD_TIMER
;
113 config
->request_time_seconds
= DEFAULT_CONFIG_REQUEST_TIME
;
114 config
->max_unknown_messages
= DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES
;
115 config
->max_unknown_requests
= DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS
;
117 config
->socket_connect_timeout_millis
=
118 DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS
;
119 config
->support_stateful_pce_lsp_update
= true;
120 config
->support_pce_lsp_instantiation
= true;
121 config
->support_include_db_version
= true;
122 config
->lsp_db_version
= 0;
123 config
->support_lsp_triggered_resync
= true;
124 config
->support_lsp_delta_sync
= true;
125 config
->support_pce_triggered_initial_sync
= true;
126 config
->support_sr_te_pst
= true;
127 config
->pcc_can_resolve_nai_to_sid
= true;
128 config
->max_sid_depth
= 0;
129 config
->dst_pcep_port
= 0;
130 config
->src_pcep_port
= 0;
131 config
->src_ip
.src_ipv4
.s_addr
= INADDR_ANY
;
132 config
->is_src_ipv6
= false;
133 config
->pcep_msg_versioning
= create_default_pcep_versioning();
134 config
->tcp_authentication_str
[0] = '\0';
135 config
->is_tcp_auth_md5
= true;
140 void destroy_pcep_configuration(pcep_configuration
*config
)
142 destroy_pcep_versioning(config
->pcep_msg_versioning
);
143 pceplib_free(PCEPLIB_INFRA
, config
);
146 pcep_session
*connect_pce(pcep_configuration
*config
, struct in_addr
*pce_ip
)
148 return create_pcep_session(config
, pce_ip
);
151 pcep_session
*connect_pce_ipv6(pcep_configuration
*config
,
152 struct in6_addr
*pce_ip
)
154 return create_pcep_session_ipv6(config
, pce_ip
);
157 void disconnect_pce(pcep_session
*session
)
159 if (session_exists(session
) == false) {
162 "%s: disconnect_pce session [%p] has already been deleted",
167 if (session
->socket_comm_session
== NULL
168 || session
->socket_comm_session
->socket_fd
< 0) {
169 /* If the socket has already been closed, just destroy the
171 destroy_pcep_session(session
);
173 /* This will cause the session to be destroyed AFTER the close
175 session
->destroy_session_after_write
= true;
177 /* Send a PCEP close message */
178 close_pcep_session(session
);
182 void send_message(pcep_session
*session
, struct pcep_message
*msg
,
183 bool free_after_send
)
185 if (session
== NULL
|| msg
== NULL
) {
187 "%s: send_message NULL params session [%p] msg [%p]",
188 __func__
, session
, msg
);
193 if (session_exists(session
) == false) {
196 "%s: send_message session [%p] has already been deleted",
201 pcep_encode_message(msg
, session
->pcc_config
.pcep_msg_versioning
);
202 socket_comm_session_send_message(
203 session
->socket_comm_session
, (char *)msg
->encoded_message
,
204 msg
->encoded_message_length
, free_after_send
);
206 increment_message_tx_counters(session
, msg
);
208 if (free_after_send
== true) {
209 /* The encoded_message will be deleted once sent, so everything
210 * else in the message will be freed */
211 msg
->encoded_message
= NULL
;
212 pcep_msg_free_message(msg
);
216 /* Returns true if the queue is empty, false otherwise */
217 bool event_queue_is_empty(void)
219 if (session_logic_event_queue_
== NULL
) {
222 "%s: event_queue_is_empty Session Logic is not initialized yet",
227 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
229 (session_logic_event_queue_
->event_queue
->num_entries
== 0);
230 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
236 /* Return the number of events on the queue, 0 if empty */
237 uint32_t event_queue_num_events_available(void)
239 if (session_logic_event_queue_
== NULL
) {
242 "%s: event_queue_num_events_available Session Logic is not initialized yet",
247 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
248 uint32_t num_events
=
249 session_logic_event_queue_
->event_queue
->num_entries
;
250 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
256 /* Return the next event on the queue, NULL if empty */
257 struct pcep_event
*event_queue_get_event(void)
259 if (session_logic_event_queue_
== NULL
) {
262 "%s: event_queue_get_event Session Logic is not initialized yet",
267 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
268 struct pcep_event
*event
= (struct pcep_event
*)queue_dequeue(
269 session_logic_event_queue_
->event_queue
);
270 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
276 /* Free the PCEP Event resources, including the PCEP message */
277 void destroy_pcep_event(struct pcep_event
*event
)
280 pcep_log(LOG_WARNING
,
281 "%s: destroy_pcep_event cannot destroy NULL event",
286 if (event
->event_type
== MESSAGE_RECEIVED
&& event
->message
!= NULL
) {
287 pcep_msg_free_message(event
->message
);
290 pceplib_free(PCEPLIB_INFRA
, event
);
293 const char *get_event_type_str(int event_type
)
295 switch (event_type
) {
296 case MESSAGE_RECEIVED
:
297 return MESSAGE_RECEIVED_STR
;
299 case PCE_CLOSED_SOCKET
:
300 return PCE_CLOSED_SOCKET_STR
;
302 case PCE_SENT_PCEP_CLOSE
:
303 return PCE_SENT_PCEP_CLOSE_STR
;
305 case PCE_DEAD_TIMER_EXPIRED
:
306 return PCE_DEAD_TIMER_EXPIRED_STR
;
308 case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED
:
309 return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR
;
311 case PCC_CONNECTED_TO_PCE
:
312 return PCC_CONNECTED_TO_PCE_STR
;
314 case PCC_PCEP_SESSION_CLOSED
:
315 return PCC_PCEP_SESSION_CLOSED_STR
;
317 case PCC_RCVD_INVALID_OPEN
:
318 return PCC_RCVD_INVALID_OPEN_STR
;
320 case PCC_RCVD_MAX_INVALID_MSGS
:
321 return PCC_RCVD_MAX_INVALID_MSGS_STR
;
323 case PCC_RCVD_MAX_UNKOWN_MSGS
:
324 return PCC_RCVD_MAX_UNKOWN_MSGS_STR
;
327 return UNKNOWN_EVENT_STR
;
332 void dump_pcep_session_counters(pcep_session
*session
)
334 if (session_exists(session
) == false) {
337 "%s: dump_pcep_session_counters session [%p] has already been deleted",
342 /* Update the counters group name so that the PCE session connected time
344 time_t now
= time(NULL
);
345 char counters_name
[MAX_COUNTER_STR_LENGTH
] = {0};
346 char ip_str
[40] = {0};
347 if (session
->socket_comm_session
->is_ipv6
) {
349 &session
->socket_comm_session
->dest_sock_addr
350 .dest_sock_addr_ipv6
.sin6_addr
,
354 &session
->socket_comm_session
->dest_sock_addr
355 .dest_sock_addr_ipv4
.sin_addr
,
358 snprintf(counters_name
, MAX_COUNTER_STR_LENGTH
,
359 "PCEP Session [%d], connected to [%s] for [%u seconds]",
360 session
->session_id
, ip_str
,
361 (uint32_t)(now
- session
->time_connected
));
362 strlcpy(session
->pcep_session_counters
->counters_group_name
,
364 sizeof(session
->pcep_session_counters
->counters_group_name
));
366 dump_counters_group_to_log(session
->pcep_session_counters
);
369 void reset_pcep_session_counters(pcep_session
*session
)
371 if (session_exists(session
) == false) {
374 "%s: reset_pcep_session_counters session [%p] has already been deleted",
379 reset_group_counters(session
->pcep_session_counters
);