]>
Commit | Line | Data |
---|---|---|
74971473 JG |
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 | * This is the implementation of a High Level PCEP message API. | |
26 | */ | |
27 | ||
1f8031f7 DL |
28 | #ifdef HAVE_CONFIG_H |
29 | #include "config.h" | |
30 | #endif | |
31 | ||
74971473 JG |
32 | #include <string.h> |
33 | #include <arpa/inet.h> | |
34 | #include <stdarg.h> | |
35 | #include <unistd.h> | |
36 | ||
37 | #include "pcep_msg_encoding.h" | |
38 | #include "pcep_msg_messages.h" | |
39 | #include "pcep_msg_objects.h" | |
40 | #include "pcep_utils_double_linked_list.h" | |
41 | #include "pcep_utils_logging.h" | |
42 | #include "pcep_utils_memory.h" | |
43 | ||
44 | static struct pcep_message * | |
45 | pcep_msg_create_common_with_obj_list(enum pcep_message_types msg_type, | |
46 | double_linked_list *obj_list) | |
47 | { | |
48 | struct pcep_message *message = | |
49 | pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message)); | |
50 | memset(message, 0, sizeof(struct pcep_message)); | |
51 | message->msg_header = pceplib_malloc( | |
52 | PCEPLIB_MESSAGES, sizeof(struct pcep_message_header)); | |
53 | memset(message->msg_header, 0, sizeof(struct pcep_message_header)); | |
54 | message->msg_header->type = msg_type; | |
55 | message->msg_header->pcep_version = PCEP_MESSAGE_HEADER_VERSION; | |
56 | message->obj_list = ((obj_list == NULL) ? dll_initialize() : obj_list); | |
57 | ||
58 | return message; | |
59 | } | |
60 | ||
61 | static struct pcep_message * | |
62 | pcep_msg_create_common(enum pcep_message_types msg_type) | |
63 | { | |
64 | return pcep_msg_create_common_with_obj_list(msg_type, NULL); | |
65 | } | |
66 | ||
67 | struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer, | |
68 | uint8_t sid) | |
69 | { | |
70 | struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN); | |
71 | dll_append(message->obj_list, | |
72 | pcep_obj_create_open(keepalive, deadtimer, sid, NULL)); | |
73 | ||
74 | return message; | |
75 | } | |
76 | ||
77 | struct pcep_message * | |
78 | pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer, | |
79 | uint8_t sid, double_linked_list *tlv_list) | |
80 | { | |
81 | struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN); | |
82 | dll_append(message->obj_list, | |
83 | pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list)); | |
84 | ||
85 | return message; | |
86 | } | |
87 | ||
88 | ||
89 | struct pcep_message * | |
90 | pcep_msg_create_request(struct pcep_object_rp *rp, | |
91 | struct pcep_object_endpoints_ipv4 *endpoints, | |
92 | double_linked_list *object_list) | |
93 | { | |
94 | if ((rp == NULL) || (endpoints == NULL)) { | |
95 | return NULL; | |
96 | } | |
97 | ||
98 | struct pcep_message *message = pcep_msg_create_common_with_obj_list( | |
99 | PCEP_TYPE_PCREQ, object_list); | |
100 | dll_prepend(message->obj_list, endpoints); | |
101 | dll_prepend(message->obj_list, rp); | |
102 | ||
103 | return message; | |
104 | } | |
105 | ||
106 | struct pcep_message * | |
107 | pcep_msg_create_request_ipv6(struct pcep_object_rp *rp, | |
108 | struct pcep_object_endpoints_ipv6 *endpoints, | |
109 | double_linked_list *object_list) | |
110 | { | |
111 | if ((rp == NULL) || (endpoints == NULL)) { | |
112 | return NULL; | |
113 | } | |
114 | ||
115 | struct pcep_message *message = pcep_msg_create_common_with_obj_list( | |
116 | PCEP_TYPE_PCREQ, object_list); | |
117 | dll_prepend(message->obj_list, endpoints); | |
118 | dll_prepend(message->obj_list, rp); | |
119 | ||
120 | return message; | |
121 | } | |
122 | ||
123 | struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp, | |
124 | double_linked_list *object_list) | |
125 | { | |
126 | struct pcep_message *message = pcep_msg_create_common_with_obj_list( | |
127 | PCEP_TYPE_PCREP, object_list); | |
128 | ||
129 | if (rp != NULL) { | |
130 | dll_prepend(message->obj_list, rp); | |
131 | } | |
132 | ||
133 | return message; | |
134 | } | |
135 | ||
136 | struct pcep_message *pcep_msg_create_close(uint8_t reason) | |
137 | { | |
138 | struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_CLOSE); | |
139 | dll_append(message->obj_list, pcep_obj_create_close(reason)); | |
140 | ||
141 | return message; | |
142 | } | |
143 | ||
144 | struct pcep_message *pcep_msg_create_error(uint8_t error_type, | |
145 | uint8_t error_value) | |
146 | { | |
147 | struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_ERROR); | |
148 | dll_append(message->obj_list, | |
149 | pcep_obj_create_error(error_type, error_value)); | |
150 | ||
151 | return message; | |
152 | } | |
153 | ||
154 | struct pcep_message * | |
155 | pcep_msg_create_error_with_objects(uint8_t error_type, uint8_t error_value, | |
156 | double_linked_list *object_list) | |
157 | { | |
158 | struct pcep_message *message = pcep_msg_create_common_with_obj_list( | |
159 | PCEP_TYPE_ERROR, object_list); | |
160 | dll_prepend(message->obj_list, | |
161 | pcep_obj_create_error(error_type, error_value)); | |
162 | ||
163 | return message; | |
164 | } | |
165 | ||
166 | struct pcep_message *pcep_msg_create_keepalive() | |
167 | { | |
168 | return (pcep_msg_create_common(PCEP_TYPE_KEEPALIVE)); | |
169 | } | |
170 | ||
171 | struct pcep_message * | |
172 | pcep_msg_create_report(double_linked_list *state_report_object_list) | |
173 | { | |
174 | return (state_report_object_list == NULL | |
175 | ? NULL | |
176 | : pcep_msg_create_common_with_obj_list( | |
177 | PCEP_TYPE_REPORT, state_report_object_list)); | |
178 | } | |
179 | ||
180 | struct pcep_message * | |
181 | pcep_msg_create_update(double_linked_list *update_request_object_list) | |
182 | { | |
183 | if (update_request_object_list == NULL) { | |
184 | pcep_log( | |
185 | LOG_INFO, | |
186 | "%s: pcep_msg_create_update NULL update_request_object_list", | |
187 | __func__); | |
188 | return NULL; | |
189 | } | |
190 | ||
191 | /* There must be at least 3 objects: | |
192 | * These 3 are mandatory: SRP, LSP, and ERO. The ERO may be empty */ | |
193 | if (update_request_object_list->num_entries < 3) { | |
194 | pcep_log( | |
195 | LOG_INFO, | |
196 | "%s: pcep_msg_create_update there must be at least 3 update objects", | |
197 | __func__); | |
198 | return NULL; | |
199 | } | |
200 | ||
201 | double_linked_list_node *node = update_request_object_list->head; | |
202 | struct pcep_object_header *obj_hdr = | |
203 | (struct pcep_object_header *)node->data; | |
204 | ||
205 | /* Check for the mandatory first SRP object */ | |
206 | if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) { | |
207 | /* If the SRP object is missing, the receiving PCC MUST send a | |
208 | * PCErr message with Error-type=6 (Mandatory Object missing) | |
209 | * and Error-value=10 (SRP object missing). */ | |
210 | pcep_log( | |
211 | LOG_INFO, | |
212 | "%s: pcep_msg_create_update missing mandatory first SRP object", | |
213 | __func__); | |
214 | return NULL; | |
215 | } | |
216 | ||
217 | /* Check for the mandatory 2nd LSP object */ | |
218 | node = node->next_node; | |
219 | obj_hdr = (struct pcep_object_header *)node->data; | |
220 | if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) { | |
221 | /* If the LSP object is missing, the receiving PCC MUST send a | |
222 | * PCErr message with Error-type=6 (Mandatory Object missing) | |
223 | * and Error-value=8 (LSP object missing). */ | |
224 | pcep_log( | |
225 | LOG_INFO, | |
226 | "%s: pcep_msg_create_update missing mandatory second LSP object", | |
227 | __func__); | |
228 | return NULL; | |
229 | } | |
230 | ||
231 | /* Check for the mandatory 3rd ERO object */ | |
232 | node = node->next_node; | |
233 | obj_hdr = (struct pcep_object_header *)node->data; | |
234 | if (obj_hdr->object_class != PCEP_OBJ_CLASS_ERO) { | |
235 | /* If the ERO object is missing, the receiving PCC MUST send a | |
236 | * PCErr message with Error-type=6 (Mandatory Object missing) | |
237 | * and Error-value=9 (ERO object missing). */ | |
238 | pcep_log( | |
239 | LOG_INFO, | |
240 | "%s: pcep_msg_create_update missing mandatory third ERO object", | |
241 | __func__); | |
242 | return NULL; | |
243 | } | |
244 | ||
245 | return (pcep_msg_create_common_with_obj_list( | |
246 | PCEP_TYPE_UPDATE, update_request_object_list)); | |
247 | } | |
248 | ||
249 | struct pcep_message * | |
250 | pcep_msg_create_initiate(double_linked_list *lsp_object_list) | |
251 | { | |
252 | if (lsp_object_list == NULL) { | |
253 | pcep_log( | |
254 | LOG_INFO, | |
255 | "%s: pcep_msg_create_initiate NULL update_request_object_list", | |
256 | __func__); | |
257 | return NULL; | |
258 | } | |
259 | ||
260 | /* There must be at least 2 objects: SRP and LSP. */ | |
261 | if (lsp_object_list->num_entries < 2) { | |
262 | pcep_log( | |
263 | LOG_INFO, | |
264 | "%s: pcep_msg_create_initiate there must be at least 2 objects", | |
265 | __func__); | |
266 | return NULL; | |
267 | } | |
268 | ||
269 | double_linked_list_node *node = lsp_object_list->head; | |
270 | struct pcep_object_header *obj_hdr = | |
271 | (struct pcep_object_header *)node->data; | |
272 | ||
273 | /* Check for the mandatory first SRP object */ | |
274 | if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) { | |
275 | pcep_log( | |
276 | LOG_INFO, | |
277 | "%s: pcep_msg_create_initiate missing mandatory first SRP object", | |
278 | __func__); | |
279 | return NULL; | |
280 | } | |
281 | ||
282 | /* Check for the mandatory 2nd LSP object */ | |
283 | node = node->next_node; | |
284 | obj_hdr = (struct pcep_object_header *)node->data; | |
285 | if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) { | |
286 | pcep_log( | |
287 | LOG_INFO, | |
288 | "%s: pcep_msg_create_initiate missing mandatory second LSP object", | |
289 | __func__); | |
290 | return NULL; | |
291 | } | |
292 | ||
293 | return (pcep_msg_create_common_with_obj_list(PCEP_TYPE_INITIATE, | |
294 | lsp_object_list)); | |
295 | } | |
296 | ||
297 | struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify, | |
298 | double_linked_list *object_list) | |
299 | { | |
300 | if (notify == NULL) { | |
301 | pcep_log(LOG_INFO, | |
302 | "%s: pcep_msg_create_notify NULL notify object", | |
303 | __func__); | |
304 | return NULL; | |
305 | } | |
306 | ||
307 | struct pcep_message *message = pcep_msg_create_common_with_obj_list( | |
308 | PCEP_TYPE_PCNOTF, object_list); | |
309 | dll_prepend(message->obj_list, notify); | |
310 | ||
311 | return message; | |
312 | } |