]> git.proxmox.com Git - mirror_frr.git/blob - pceplib/pcep_pcc_api.c
Merge pull request #12751 from Pdoijode/pdoijode/ospf-vrf-neighbor-detail-1
[mirror_frr.git] / pceplib / pcep_pcc_api.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3 * This file is part of the PCEPlib, a PCEP protocol library.
4 *
5 * Copyright (C) 2020 Volta Networks https://voltanet.io/
6 *
7 * Author : Brady Johnson <brady@voltanet.io>
8 *
9 */
10
11
12 /*
13 * Public PCEPlib PCC API implementation
14 */
15
16 #include <zebra.h>
17
18 #include <pthread.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "pcep_msg_messages.h"
24 #include "pcep_pcc_api.h"
25 #include "pcep_utils_counters.h"
26 #include "pcep_utils_logging.h"
27
28 /* Not using an array here since the enum pcep_event_type indeces go into the
29 * 100's */
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";
42
43 /* Session Logic Handle managed in pcep_session_logic.c */
44 extern pcep_event_queue *session_logic_event_queue_;
45
46 bool initialize_pcc(void)
47 {
48 if (!run_session_logic()) {
49 pcep_log(LOG_ERR, "%s: Error initializing PCC session logic.",
50 __func__);
51 return false;
52 }
53
54 return true;
55 }
56
57
58 bool initialize_pcc_infra(struct pceplib_infra_config *infra_config)
59 {
60 if (infra_config == NULL) {
61 return initialize_pcc();
62 }
63
64 if (!run_session_logic_with_infra(infra_config)) {
65 pcep_log(LOG_ERR,
66 "%s: Error initializing PCC session logic with infra.",
67 __func__);
68 return false;
69 }
70
71 return true;
72 }
73
74
75 /* this function is blocking */
76 bool initialize_pcc_wait_for_completion(void)
77 {
78 return run_session_logic_wait_for_completion();
79 }
80
81
82 bool destroy_pcc(void)
83 {
84 if (!stop_session_logic()) {
85 pcep_log(LOG_WARNING, "%s: Error stopping PCC session logic.",
86 __func__);
87 return false;
88 }
89
90 return true;
91 }
92
93
94 pcep_configuration *create_default_pcep_configuration(void)
95 {
96 pcep_configuration *config =
97 pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_configuration));
98 memset(config, 0, sizeof(pcep_configuration));
99
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;
106
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;
112
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;
116
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;
136
137 return config;
138 }
139
140 void destroy_pcep_configuration(pcep_configuration *config)
141 {
142 destroy_pcep_versioning(config->pcep_msg_versioning);
143 pceplib_free(PCEPLIB_INFRA, config);
144 }
145
146 pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip)
147 {
148 return create_pcep_session(config, pce_ip);
149 }
150
151 pcep_session *connect_pce_ipv6(pcep_configuration *config,
152 struct in6_addr *pce_ip)
153 {
154 return create_pcep_session_ipv6(config, pce_ip);
155 }
156
157 void disconnect_pce(pcep_session *session)
158 {
159 if (session_exists(session) == false) {
160 pcep_log(
161 LOG_WARNING,
162 "%s: disconnect_pce session [%p] has already been deleted",
163 __func__, session);
164 return;
165 }
166
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
170 * session */
171 destroy_pcep_session(session);
172 } else {
173 /* This will cause the session to be destroyed AFTER the close
174 * message is sent */
175 session->destroy_session_after_write = true;
176
177 /* Send a PCEP close message */
178 close_pcep_session(session);
179 }
180 }
181
182 void send_message(pcep_session *session, struct pcep_message *msg,
183 bool free_after_send)
184 {
185 if (session == NULL || msg == NULL) {
186 pcep_log(LOG_DEBUG,
187 "%s: send_message NULL params session [%p] msg [%p]",
188 __func__, session, msg);
189
190 return;
191 }
192
193 if (session_exists(session) == false) {
194 pcep_log(
195 LOG_WARNING,
196 "%s: send_message session [%p] has already been deleted",
197 __func__, session);
198 return;
199 }
200
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);
205
206 increment_message_tx_counters(session, msg);
207
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);
213 }
214 }
215
216 /* Returns true if the queue is empty, false otherwise */
217 bool event_queue_is_empty(void)
218 {
219 if (session_logic_event_queue_ == NULL) {
220 pcep_log(
221 LOG_WARNING,
222 "%s: event_queue_is_empty Session Logic is not initialized yet",
223 __func__);
224 return false;
225 }
226
227 pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
228 bool is_empty =
229 (session_logic_event_queue_->event_queue->num_entries == 0);
230 pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
231
232 return is_empty;
233 }
234
235
236 /* Return the number of events on the queue, 0 if empty */
237 uint32_t event_queue_num_events_available(void)
238 {
239 if (session_logic_event_queue_ == NULL) {
240 pcep_log(
241 LOG_WARNING,
242 "%s: event_queue_num_events_available Session Logic is not initialized yet",
243 __func__);
244 return 0;
245 }
246
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);
251
252 return num_events;
253 }
254
255
256 /* Return the next event on the queue, NULL if empty */
257 struct pcep_event *event_queue_get_event(void)
258 {
259 if (session_logic_event_queue_ == NULL) {
260 pcep_log(
261 LOG_WARNING,
262 "%s: event_queue_get_event Session Logic is not initialized yet",
263 __func__);
264 return NULL;
265 }
266
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);
271
272 return event;
273 }
274
275
276 /* Free the PCEP Event resources, including the PCEP message */
277 void destroy_pcep_event(struct pcep_event *event)
278 {
279 if (event == NULL) {
280 pcep_log(LOG_WARNING,
281 "%s: destroy_pcep_event cannot destroy NULL event",
282 __func__);
283 return;
284 }
285
286 if (event->event_type == MESSAGE_RECEIVED && event->message != NULL) {
287 pcep_msg_free_message(event->message);
288 }
289
290 pceplib_free(PCEPLIB_INFRA, event);
291 }
292
293 const char *get_event_type_str(int event_type)
294 {
295 switch (event_type) {
296 case MESSAGE_RECEIVED:
297 return MESSAGE_RECEIVED_STR;
298 break;
299 case PCE_CLOSED_SOCKET:
300 return PCE_CLOSED_SOCKET_STR;
301 break;
302 case PCE_SENT_PCEP_CLOSE:
303 return PCE_SENT_PCEP_CLOSE_STR;
304 break;
305 case PCE_DEAD_TIMER_EXPIRED:
306 return PCE_DEAD_TIMER_EXPIRED_STR;
307 break;
308 case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED:
309 return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR;
310 break;
311 case PCC_CONNECTED_TO_PCE:
312 return PCC_CONNECTED_TO_PCE_STR;
313 break;
314 case PCC_PCEP_SESSION_CLOSED:
315 return PCC_PCEP_SESSION_CLOSED_STR;
316 break;
317 case PCC_RCVD_INVALID_OPEN:
318 return PCC_RCVD_INVALID_OPEN_STR;
319 break;
320 case PCC_RCVD_MAX_INVALID_MSGS:
321 return PCC_RCVD_MAX_INVALID_MSGS_STR;
322 break;
323 case PCC_RCVD_MAX_UNKOWN_MSGS:
324 return PCC_RCVD_MAX_UNKOWN_MSGS_STR;
325 break;
326 default:
327 return UNKNOWN_EVENT_STR;
328 break;
329 }
330 }
331
332 void dump_pcep_session_counters(pcep_session *session)
333 {
334 if (session_exists(session) == false) {
335 pcep_log(
336 LOG_WARNING,
337 "%s: dump_pcep_session_counters session [%p] has already been deleted",
338 __func__, session);
339 return;
340 }
341
342 /* Update the counters group name so that the PCE session connected time
343 * is accurate */
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) {
348 inet_ntop(AF_INET6,
349 &session->socket_comm_session->dest_sock_addr
350 .dest_sock_addr_ipv6.sin6_addr,
351 ip_str, 40);
352 } else {
353 inet_ntop(AF_INET,
354 &session->socket_comm_session->dest_sock_addr
355 .dest_sock_addr_ipv4.sin_addr,
356 ip_str, 40);
357 }
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,
363 counters_name,
364 sizeof(session->pcep_session_counters->counters_group_name));
365
366 dump_counters_group_to_log(session->pcep_session_counters);
367 }
368
369 void reset_pcep_session_counters(pcep_session *session)
370 {
371 if (session_exists(session) == false) {
372 pcep_log(
373 LOG_WARNING,
374 "%s: reset_pcep_session_counters session [%p] has already been deleted",
375 session);
376 return;
377 }
378
379 reset_group_counters(session->pcep_session_counters);
380 }