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