]> git.proxmox.com Git - mirror_frr.git/blob - pceplib/pcep_pcc_api.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / pceplib / pcep_pcc_api.c
1 /*
2 * This file is part of the PCEPlib, a PCEP protocol library.
3 *
4 * Copyright (C) 2020 Volta Networks https://voltanet.io/
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author : Brady Johnson <brady@voltanet.io>
20 *
21 */
22
23
24 /*
25 * Public PCEPlib PCC API implementation
26 */
27
28 #include <zebra.h>
29
30 #include <pthread.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 #include "pcep_msg_messages.h"
36 #include "pcep_pcc_api.h"
37 #include "pcep_utils_counters.h"
38 #include "pcep_utils_logging.h"
39
40 /* Not using an array here since the enum pcep_event_type indeces go into the
41 * 100's */
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";
54
55 /* Session Logic Handle managed in pcep_session_logic.c */
56 extern pcep_event_queue *session_logic_event_queue_;
57
58 bool initialize_pcc(void)
59 {
60 if (!run_session_logic()) {
61 pcep_log(LOG_ERR, "%s: Error initializing PCC session logic.",
62 __func__);
63 return false;
64 }
65
66 return true;
67 }
68
69
70 bool initialize_pcc_infra(struct pceplib_infra_config *infra_config)
71 {
72 if (infra_config == NULL) {
73 return initialize_pcc();
74 }
75
76 if (!run_session_logic_with_infra(infra_config)) {
77 pcep_log(LOG_ERR,
78 "%s: Error initializing PCC session logic with infra.",
79 __func__);
80 return false;
81 }
82
83 return true;
84 }
85
86
87 /* this function is blocking */
88 bool initialize_pcc_wait_for_completion(void)
89 {
90 return run_session_logic_wait_for_completion();
91 }
92
93
94 bool destroy_pcc(void)
95 {
96 if (!stop_session_logic()) {
97 pcep_log(LOG_WARNING, "%s: Error stopping PCC session logic.",
98 __func__);
99 return false;
100 }
101
102 return true;
103 }
104
105
106 pcep_configuration *create_default_pcep_configuration(void)
107 {
108 pcep_configuration *config =
109 pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_configuration));
110 memset(config, 0, sizeof(pcep_configuration));
111
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;
118
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;
124
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;
128
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;
148
149 return config;
150 }
151
152 void destroy_pcep_configuration(pcep_configuration *config)
153 {
154 destroy_pcep_versioning(config->pcep_msg_versioning);
155 pceplib_free(PCEPLIB_INFRA, config);
156 }
157
158 pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip)
159 {
160 return create_pcep_session(config, pce_ip);
161 }
162
163 pcep_session *connect_pce_ipv6(pcep_configuration *config,
164 struct in6_addr *pce_ip)
165 {
166 return create_pcep_session_ipv6(config, pce_ip);
167 }
168
169 void disconnect_pce(pcep_session *session)
170 {
171 if (session_exists(session) == false) {
172 pcep_log(
173 LOG_WARNING,
174 "%s: disconnect_pce session [%p] has already been deleted",
175 __func__, session);
176 return;
177 }
178
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
182 * session */
183 destroy_pcep_session(session);
184 } else {
185 /* This will cause the session to be destroyed AFTER the close
186 * message is sent */
187 session->destroy_session_after_write = true;
188
189 /* Send a PCEP close message */
190 close_pcep_session(session);
191 }
192 }
193
194 void send_message(pcep_session *session, struct pcep_message *msg,
195 bool free_after_send)
196 {
197 if (session == NULL || msg == NULL) {
198 pcep_log(LOG_DEBUG,
199 "%s: send_message NULL params session [%p] msg [%p]",
200 __func__, session, msg);
201
202 return;
203 }
204
205 if (session_exists(session) == false) {
206 pcep_log(
207 LOG_WARNING,
208 "%s: send_message session [%p] has already been deleted",
209 __func__, session);
210 return;
211 }
212
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);
217
218 increment_message_tx_counters(session, msg);
219
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);
225 }
226 }
227
228 /* Returns true if the queue is empty, false otherwise */
229 bool event_queue_is_empty(void)
230 {
231 if (session_logic_event_queue_ == NULL) {
232 pcep_log(
233 LOG_WARNING,
234 "%s: event_queue_is_empty Session Logic is not initialized yet",
235 __func__);
236 return false;
237 }
238
239 pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
240 bool is_empty =
241 (session_logic_event_queue_->event_queue->num_entries == 0);
242 pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
243
244 return is_empty;
245 }
246
247
248 /* Return the number of events on the queue, 0 if empty */
249 uint32_t event_queue_num_events_available(void)
250 {
251 if (session_logic_event_queue_ == NULL) {
252 pcep_log(
253 LOG_WARNING,
254 "%s: event_queue_num_events_available Session Logic is not initialized yet",
255 __func__);
256 return 0;
257 }
258
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);
263
264 return num_events;
265 }
266
267
268 /* Return the next event on the queue, NULL if empty */
269 struct pcep_event *event_queue_get_event(void)
270 {
271 if (session_logic_event_queue_ == NULL) {
272 pcep_log(
273 LOG_WARNING,
274 "%s: event_queue_get_event Session Logic is not initialized yet",
275 __func__);
276 return NULL;
277 }
278
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);
283
284 return event;
285 }
286
287
288 /* Free the PCEP Event resources, including the PCEP message */
289 void destroy_pcep_event(struct pcep_event *event)
290 {
291 if (event == NULL) {
292 pcep_log(LOG_WARNING,
293 "%s: destroy_pcep_event cannot destroy NULL event",
294 __func__);
295 return;
296 }
297
298 if (event->event_type == MESSAGE_RECEIVED && event->message != NULL) {
299 pcep_msg_free_message(event->message);
300 }
301
302 pceplib_free(PCEPLIB_INFRA, event);
303 }
304
305 const char *get_event_type_str(int event_type)
306 {
307 switch (event_type) {
308 case MESSAGE_RECEIVED:
309 return MESSAGE_RECEIVED_STR;
310 break;
311 case PCE_CLOSED_SOCKET:
312 return PCE_CLOSED_SOCKET_STR;
313 break;
314 case PCE_SENT_PCEP_CLOSE:
315 return PCE_SENT_PCEP_CLOSE_STR;
316 break;
317 case PCE_DEAD_TIMER_EXPIRED:
318 return PCE_DEAD_TIMER_EXPIRED_STR;
319 break;
320 case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED:
321 return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR;
322 break;
323 case PCC_CONNECTED_TO_PCE:
324 return PCC_CONNECTED_TO_PCE_STR;
325 break;
326 case PCC_PCEP_SESSION_CLOSED:
327 return PCC_PCEP_SESSION_CLOSED_STR;
328 break;
329 case PCC_RCVD_INVALID_OPEN:
330 return PCC_RCVD_INVALID_OPEN_STR;
331 break;
332 case PCC_RCVD_MAX_INVALID_MSGS:
333 return PCC_RCVD_MAX_INVALID_MSGS_STR;
334 break;
335 case PCC_RCVD_MAX_UNKOWN_MSGS:
336 return PCC_RCVD_MAX_UNKOWN_MSGS_STR;
337 break;
338 default:
339 return UNKNOWN_EVENT_STR;
340 break;
341 }
342 }
343
344 void dump_pcep_session_counters(pcep_session *session)
345 {
346 if (session_exists(session) == false) {
347 pcep_log(
348 LOG_WARNING,
349 "%s: dump_pcep_session_counters session [%p] has already been deleted",
350 __func__, session);
351 return;
352 }
353
354 /* Update the counters group name so that the PCE session connected time
355 * is accurate */
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) {
360 inet_ntop(AF_INET6,
361 &session->socket_comm_session->dest_sock_addr
362 .dest_sock_addr_ipv6.sin6_addr,
363 ip_str, 40);
364 } else {
365 inet_ntop(AF_INET,
366 &session->socket_comm_session->dest_sock_addr
367 .dest_sock_addr_ipv4.sin_addr,
368 ip_str, 40);
369 }
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,
375 counters_name,
376 sizeof(session->pcep_session_counters->counters_group_name));
377
378 dump_counters_group_to_log(session->pcep_session_counters);
379 }
380
381 void reset_pcep_session_counters(pcep_session *session)
382 {
383 if (session_exists(session) == false) {
384 pcep_log(
385 LOG_WARNING,
386 "%s: reset_pcep_session_counters session [%p] has already been deleted",
387 session);
388 return;
389 }
390
391 reset_group_counters(session->pcep_session_counters);
392 }