2 * This file is part of the PCEPlib, a PCEP protocol library.
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * Author : Brady Johnson <brady@voltanet.io>
25 * Public PCEPlib PCC API implementation
35 #include "pcep_msg_messages.h"
36 #include "pcep_pcc_api.h"
37 #include "pcep_utils_counters.h"
38 #include "pcep_utils_logging.h"
40 /* Not using an array here since the enum pcep_event_type indeces go into the
42 const char MESSAGE_RECEIVED_STR
[] = "MESSAGE_RECEIVED";
43 const char PCE_CLOSED_SOCKET_STR
[] = "PCE_CLOSED_SOCKET";
44 const char PCE_SENT_PCEP_CLOSE_STR
[] = "PCE_SENT_PCEP_CLOSE";
45 const char PCE_DEAD_TIMER_EXPIRED_STR
[] = "PCE_DEAD_TIMER_EXPIRED";
46 const char PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR
[] =
47 "PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED";
48 const char PCC_CONNECTED_TO_PCE_STR
[] = "PCC_CONNECTED_TO_PCE";
49 const char PCC_PCEP_SESSION_CLOSED_STR
[] = "PCC_PCEP_SESSION_CLOSED";
50 const char PCC_RCVD_INVALID_OPEN_STR
[] = "PCC_RCVD_INVALID_OPEN";
51 const char PCC_RCVD_MAX_INVALID_MSGS_STR
[] = "PCC_RCVD_MAX_INVALID_MSGS";
52 const char PCC_RCVD_MAX_UNKOWN_MSGS_STR
[] = "PCC_RCVD_MAX_UNKOWN_MSGS";
53 const char UNKNOWN_EVENT_STR
[] = "UNKNOWN Event Type";
55 /* Session Logic Handle managed in pcep_session_logic.c */
56 extern pcep_event_queue
*session_logic_event_queue_
;
60 if (!run_session_logic()) {
61 pcep_log(LOG_ERR
, "%s: Error initializing PCC session logic.",
70 bool initialize_pcc_infra(struct pceplib_infra_config
*infra_config
)
72 if (infra_config
== NULL
) {
73 return initialize_pcc();
76 if (!run_session_logic_with_infra(infra_config
)) {
78 "%s: Error initializing PCC session logic with infra.",
87 /* this function is blocking */
88 bool initialize_pcc_wait_for_completion()
90 return run_session_logic_wait_for_completion();
96 if (!stop_session_logic()) {
97 pcep_log(LOG_WARNING
, "%s: Error stopping PCC session logic.",
106 pcep_configuration
*create_default_pcep_configuration()
108 pcep_configuration
*config
=
109 pceplib_malloc(PCEPLIB_INFRA
, sizeof(pcep_configuration
));
110 memset(config
, 0, sizeof(pcep_configuration
));
112 config
->keep_alive_seconds
= DEFAULT_CONFIG_KEEP_ALIVE
;
113 /* This value will possibly be overwritten later with PCE config data */
114 config
->keep_alive_pce_negotiated_timer_seconds
=
115 DEFAULT_CONFIG_KEEP_ALIVE
;
116 config
->min_keep_alive_seconds
= DEFAULT_MIN_CONFIG_KEEP_ALIVE
;
117 config
->max_keep_alive_seconds
= DEFAULT_MAX_CONFIG_KEEP_ALIVE
;
119 config
->dead_timer_seconds
= DEFAULT_CONFIG_DEAD_TIMER
;
120 /* This value will be overwritten later with PCE config data */
121 config
->dead_timer_pce_negotiated_seconds
= DEFAULT_CONFIG_DEAD_TIMER
;
122 config
->min_dead_timer_seconds
= DEFAULT_MIN_CONFIG_DEAD_TIMER
;
123 config
->max_dead_timer_seconds
= DEFAULT_MAX_CONFIG_DEAD_TIMER
;
125 config
->request_time_seconds
= DEFAULT_CONFIG_REQUEST_TIME
;
126 config
->max_unknown_messages
= DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES
;
127 config
->max_unknown_requests
= DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS
;
129 config
->socket_connect_timeout_millis
=
130 DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS
;
131 config
->support_stateful_pce_lsp_update
= true;
132 config
->support_pce_lsp_instantiation
= true;
133 config
->support_include_db_version
= true;
134 config
->lsp_db_version
= 0;
135 config
->support_lsp_triggered_resync
= true;
136 config
->support_lsp_delta_sync
= true;
137 config
->support_pce_triggered_initial_sync
= true;
138 config
->support_sr_te_pst
= true;
139 config
->pcc_can_resolve_nai_to_sid
= true;
140 config
->max_sid_depth
= 0;
141 config
->dst_pcep_port
= 0;
142 config
->src_pcep_port
= 0;
143 config
->src_ip
.src_ipv4
.s_addr
= INADDR_ANY
;
144 config
->is_src_ipv6
= false;
145 config
->pcep_msg_versioning
= create_default_pcep_versioning();
146 config
->tcp_authentication_str
[0] = '\0';
147 config
->is_tcp_auth_md5
= true;
152 void destroy_pcep_configuration(pcep_configuration
*config
)
154 destroy_pcep_versioning(config
->pcep_msg_versioning
);
155 pceplib_free(PCEPLIB_INFRA
, config
);
158 pcep_session
*connect_pce(pcep_configuration
*config
, struct in_addr
*pce_ip
)
160 return create_pcep_session(config
, pce_ip
);
163 pcep_session
*connect_pce_ipv6(pcep_configuration
*config
,
164 struct in6_addr
*pce_ip
)
166 return create_pcep_session_ipv6(config
, pce_ip
);
169 void disconnect_pce(pcep_session
*session
)
171 if (session_exists(session
) == false) {
174 "%s: disconnect_pce session [%p] has already been deleted",
179 if (session
->socket_comm_session
== NULL
180 || session
->socket_comm_session
->socket_fd
< 0) {
181 /* If the socket has already been closed, just destroy the
183 destroy_pcep_session(session
);
185 /* This will cause the session to be destroyed AFTER the close
187 session
->destroy_session_after_write
= true;
189 /* Send a PCEP close message */
190 close_pcep_session(session
);
194 void send_message(pcep_session
*session
, struct pcep_message
*msg
,
195 bool free_after_send
)
197 if (session
== NULL
|| msg
== NULL
) {
199 "%s: send_message NULL params session [%p] msg [%p]",
200 __func__
, session
, msg
);
205 if (session_exists(session
) == false) {
208 "%s: send_message session [%p] has already been deleted",
213 pcep_encode_message(msg
, session
->pcc_config
.pcep_msg_versioning
);
214 socket_comm_session_send_message(
215 session
->socket_comm_session
, (char *)msg
->encoded_message
,
216 msg
->encoded_message_length
, free_after_send
);
218 increment_message_tx_counters(session
, msg
);
220 if (free_after_send
== true) {
221 /* The encoded_message will be deleted once sent, so everything
222 * else in the message will be freed */
223 msg
->encoded_message
= NULL
;
224 pcep_msg_free_message(msg
);
228 /* Returns true if the queue is empty, false otherwise */
229 bool event_queue_is_empty()
231 if (session_logic_event_queue_
== NULL
) {
234 "%s: event_queue_is_empty Session Logic is not initialized yet",
239 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
241 (session_logic_event_queue_
->event_queue
->num_entries
== 0);
242 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
248 /* Return the number of events on the queue, 0 if empty */
249 uint32_t event_queue_num_events_available()
251 if (session_logic_event_queue_
== NULL
) {
254 "%s: event_queue_num_events_available Session Logic is not initialized yet",
259 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
260 uint32_t num_events
=
261 session_logic_event_queue_
->event_queue
->num_entries
;
262 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
268 /* Return the next event on the queue, NULL if empty */
269 struct pcep_event
*event_queue_get_event()
271 if (session_logic_event_queue_
== NULL
) {
274 "%s: event_queue_get_event Session Logic is not initialized yet",
279 pthread_mutex_lock(&session_logic_event_queue_
->event_queue_mutex
);
280 struct pcep_event
*event
= (struct pcep_event
*)queue_dequeue(
281 session_logic_event_queue_
->event_queue
);
282 pthread_mutex_unlock(&session_logic_event_queue_
->event_queue_mutex
);
288 /* Free the PCEP Event resources, including the PCEP message */
289 void destroy_pcep_event(struct pcep_event
*event
)
292 pcep_log(LOG_WARNING
,
293 "%s: destroy_pcep_event cannot destroy NULL event",
298 if (event
->event_type
== MESSAGE_RECEIVED
&& event
->message
!= NULL
) {
299 pcep_msg_free_message(event
->message
);
302 pceplib_free(PCEPLIB_INFRA
, event
);
305 const char *get_event_type_str(int event_type
)
307 switch (event_type
) {
308 case MESSAGE_RECEIVED
:
309 return MESSAGE_RECEIVED_STR
;
311 case PCE_CLOSED_SOCKET
:
312 return PCE_CLOSED_SOCKET_STR
;
314 case PCE_SENT_PCEP_CLOSE
:
315 return PCE_SENT_PCEP_CLOSE_STR
;
317 case PCE_DEAD_TIMER_EXPIRED
:
318 return PCE_DEAD_TIMER_EXPIRED_STR
;
320 case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED
:
321 return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR
;
323 case PCC_CONNECTED_TO_PCE
:
324 return PCC_CONNECTED_TO_PCE_STR
;
326 case PCC_PCEP_SESSION_CLOSED
:
327 return PCC_PCEP_SESSION_CLOSED_STR
;
329 case PCC_RCVD_INVALID_OPEN
:
330 return PCC_RCVD_INVALID_OPEN_STR
;
332 case PCC_RCVD_MAX_INVALID_MSGS
:
333 return PCC_RCVD_MAX_INVALID_MSGS_STR
;
335 case PCC_RCVD_MAX_UNKOWN_MSGS
:
336 return PCC_RCVD_MAX_UNKOWN_MSGS_STR
;
339 return UNKNOWN_EVENT_STR
;
344 void dump_pcep_session_counters(pcep_session
*session
)
346 if (session_exists(session
) == false) {
349 "%s: dump_pcep_session_counters session [%p] has already been deleted",
354 /* Update the counters group name so that the PCE session connected time
356 time_t now
= time(NULL
);
357 char counters_name
[MAX_COUNTER_STR_LENGTH
] = {0};
358 char ip_str
[40] = {0};
359 if (session
->socket_comm_session
->is_ipv6
) {
361 &session
->socket_comm_session
->dest_sock_addr
362 .dest_sock_addr_ipv6
.sin6_addr
,
366 &session
->socket_comm_session
->dest_sock_addr
367 .dest_sock_addr_ipv4
.sin_addr
,
370 snprintf(counters_name
, MAX_COUNTER_STR_LENGTH
,
371 "PCEP Session [%d], connected to [%s] for [%u seconds]",
372 session
->session_id
, ip_str
,
373 (uint32_t)(now
- session
->time_connected
));
374 strlcpy(session
->pcep_session_counters
->counters_group_name
,
376 sizeof(session
->pcep_session_counters
->counters_group_name
));
378 dump_counters_group_to_log(session
->pcep_session_counters
);
381 void reset_pcep_session_counters(pcep_session
*session
)
383 if (session_exists(session
) == false) {
386 "%s: reset_pcep_session_counters session [%p] has already been deleted",
391 reset_group_counters(session
->pcep_session_counters
);