Line data Source code
1 : /*
2 : * vr_message.c -- message protocol and transport independent interface for
3 : * vrouter
4 : *
5 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
6 : * Copyright Contributors to the OpenSDN project
7 : */
8 : #include <vr_os.h>
9 : #include <vrouter.h>
10 : #include "vr_message.h"
11 :
12 : static char *
13 0 : vr_message_default_malloc(unsigned int size)
14 : {
15 0 : return vr_malloc(size, VR_MESSAGE_OBJECT);
16 : }
17 :
18 : static void
19 0 : vr_message_default_free(char *buf)
20 : {
21 0 : if (buf)
22 0 : vr_free(buf, VR_MESSAGE_OBJECT);
23 0 : return;
24 : }
25 :
26 : static struct vr_mtransport default_transport = {
27 : .mtrans_alloc = vr_message_default_malloc,
28 : .mtrans_free = vr_message_default_free,
29 : };
30 :
31 : static struct vr_message_handler message_h = {
32 : .vm_trans = &default_transport,
33 : };
34 :
35 : void *
36 0 : vr_mtrans_alloc(unsigned int size)
37 : {
38 0 : if (!message_h.vm_trans)
39 0 : return NULL;
40 :
41 0 : return message_h.vm_trans->mtrans_alloc(size);
42 : }
43 :
44 : void
45 2863 : vr_mtrans_free(void *buf)
46 : {
47 2863 : if (!message_h.vm_trans)
48 0 : return;
49 :
50 2863 : message_h.vm_trans->mtrans_free(buf);
51 2863 : return;
52 : }
53 :
54 : int
55 2862 : vr_message_request(struct vr_message *message)
56 : {
57 : int ret;
58 :
59 2862 : if (!message_h.vm_proto)
60 0 : return 0;
61 :
62 2862 : if (vr_not_ready)
63 0 : return -ENETRESET;
64 :
65 2862 : if (vr_not_ready)
66 0 : return -EBADFD;
67 :
68 2862 : ret = message_h.vm_proto->mproto_decode(message->vr_message_buf,
69 : message->vr_message_len, NULL, NULL);
70 2862 : if (ret < 0)
71 0 : return ret;
72 :
73 2862 : return 0;
74 : }
75 :
76 : uint32_t g_counter = 0;
77 : static int
78 2863 : vr_message_queue_response(char *buf, int len, bool broadcast)
79 : {
80 : struct vr_message *response;
81 :
82 2863 : response = vr_zalloc(sizeof(*response), VR_MESSAGE_RESPONSE_OBJECT);
83 2863 : if (!response)
84 0 : return -ENOMEM;
85 :
86 2863 : response->vr_message_buf = buf;
87 2863 : response->vr_message_len = len;
88 2863 : response->vr_message_broadcast = broadcast;
89 2863 : vr_queue_enqueue(&message_h.vm_response_queue,
90 : &response->vr_message_queue);
91 :
92 2863 : return 0;
93 : }
94 :
95 : struct vr_message *
96 5725 : vr_message_dequeue_response(void)
97 : {
98 : struct vr_qelem *elem;
99 :
100 5725 : elem = vr_queue_dequeue(&message_h.vm_response_queue);
101 5725 : if (elem)
102 2863 : return CONTAINER_OF(vr_message_queue, struct vr_message, elem);
103 :
104 2862 : return NULL;
105 : }
106 :
107 : bool
108 2863 : vr_response_queue_empty(void)
109 : {
110 2863 : return vr_queue_empty(&message_h.vm_response_queue);
111 : }
112 :
113 : void
114 2863 : vr_message_free(struct vr_message *message)
115 : {
116 2863 : if (message) {
117 2863 : if (message->vr_message_buf)
118 2863 : vr_mtrans_free(message->vr_message_buf);
119 2863 : vr_free(message, VR_MESSAGE_RESPONSE_OBJECT);
120 : }
121 :
122 2863 : return;
123 : }
124 :
125 : int
126 0 : vr_message_make_request(unsigned int object_type, void *object)
127 : {
128 0 : char *buf = NULL;
129 : int ret;
130 : unsigned int len;
131 : struct vr_mproto *proto;
132 : struct vr_mtransport *trans;
133 : struct vr_message request;
134 :
135 0 : proto = message_h.vm_proto;
136 0 : trans = message_h.vm_trans;
137 0 : if (!proto || !trans)
138 0 : return 0;
139 :
140 0 : len = proto->mproto_buf_len(object_type, object);
141 0 : buf = trans->mtrans_alloc(len);
142 0 : if (!buf)
143 0 : return -ENOMEM;
144 :
145 0 : ret = proto->mproto_encode(buf, len, object_type, object,
146 : VR_MESSAGE_TYPE_REQUEST);
147 0 : if (ret < 0)
148 0 : goto request_fail;
149 :
150 0 : request.vr_message_buf = buf;
151 0 : request.vr_message_len = ret;
152 :
153 0 : vr_message_request(&request);
154 :
155 0 : request_fail:
156 0 : if (buf)
157 0 : trans->mtrans_free(buf);
158 :
159 0 : return ret;
160 : }
161 :
162 : int
163 0 : vr_message_process_response(int (*cb)(void *, unsigned int, void *),
164 : void *cb_arg)
165 : {
166 : struct vr_message *response;
167 : struct vr_mproto *proto;
168 : struct vr_mtransport *trans;
169 :
170 0 : proto = message_h.vm_proto;
171 0 : trans = message_h.vm_trans;
172 0 : if (!proto || !trans)
173 0 : return 0;
174 :
175 0 : while ((response = vr_message_dequeue_response())) {
176 0 : proto->mproto_decode(response->vr_message_buf,
177 : response->vr_message_len, cb, cb_arg);
178 0 : vr_message_free(response);
179 : }
180 :
181 0 : return 0;
182 : }
183 :
184 : int
185 158 : vr_message_multi_response(struct vr_message_multi *objects)
186 : {
187 158 : char *buf = NULL;
188 158 : int ret = 0;
189 158 : unsigned int i, buf_len = 0, len = 0;
190 158 : struct vr_mproto *proto = NULL;
191 158 : struct vr_mtransport *trans = NULL;
192 :
193 158 : if ((!objects) ||
194 158 : (objects->vr_mm_object_count >= VR_MESSAGE_MULTI_MAX_OBJECTS))
195 0 : goto response_fail;
196 :
197 158 : proto = message_h.vm_proto;
198 158 : trans = message_h.vm_trans;
199 158 : if (!proto || !trans)
200 0 : goto response_fail;
201 :
202 :
203 474 : for (i = 0; i < objects->vr_mm_object_count; i++) {
204 316 : buf_len += proto->mproto_buf_len(objects->vr_mm_object_type[i],
205 : objects->vr_mm_object[i]);
206 : }
207 :
208 158 : if (!buf_len)
209 0 : goto response_fail;
210 :
211 158 : buf = trans->mtrans_alloc(buf_len);
212 158 : if (!buf) {
213 0 : ret = -ENOMEM;
214 0 : goto response_fail;
215 : }
216 :
217 474 : for (i = 0; i < objects->vr_mm_object_count; i++) {
218 316 : ret = proto->mproto_encode(buf + len, buf_len - len, objects->vr_mm_object_type[i],
219 : objects->vr_mm_object[i], VR_MESSAGE_TYPE_RESPONSE);
220 316 : if (ret < 0)
221 0 : goto response_fail;
222 :
223 316 : len += ret;
224 : }
225 :
226 158 : return vr_message_queue_response(buf, len, false);
227 :
228 0 : response_fail:
229 0 : if (trans && buf)
230 0 : trans->mtrans_free(buf);
231 0 : vr_send_response(ret);
232 :
233 0 : return ret;
234 :
235 : }
236 :
237 : int
238 2704 : vr_message_response(unsigned int object_type, void *object, int ret, bool broadcast)
239 : {
240 2704 : char *buf = NULL;
241 2704 : unsigned int len = 0;
242 : struct vr_mproto *proto;
243 : struct vr_mtransport *trans;
244 :
245 2704 : proto = message_h.vm_proto;
246 2704 : trans = message_h.vm_trans;
247 2704 : if (!proto || !trans)
248 0 : return 0;
249 :
250 :
251 2704 : len = proto->mproto_buf_len(object_type, object);
252 2704 : len += proto->mproto_buf_len(VR_RESPONSE_OBJECT_ID, NULL);
253 :
254 2704 : buf = trans->mtrans_alloc(len);
255 2704 : if (!buf)
256 0 : return -ENOMEM;
257 :
258 2704 : ret = proto->mproto_encode_response(buf, len, object_type,
259 : object, ret);
260 2704 : if (ret < 0)
261 0 : goto response_fail;
262 :
263 2704 : return vr_message_queue_response(buf, ret, broadcast);
264 :
265 0 : response_fail:
266 0 : if (buf)
267 0 : trans->mtrans_free(buf);
268 :
269 0 : vr_send_response(ret);
270 0 : return ret;
271 : }
272 :
273 : int
274 1994 : vr_send_response(int code)
275 : {
276 1994 : return vr_message_response(VR_NULL_OBJECT_ID, NULL, code, false);
277 : }
278 :
279 : int
280 709 : vr_send_broadcast(unsigned int object_type, void *object, unsigned int sandesh_op, int code)
281 : {
282 709 : if (!vr_nl_broadcast_supported)
283 709 : return 0;
284 : // We only broadcast requests that have succeeded
285 0 : if (code >= 0)
286 0 : return vr_message_response(object_type, object, code, true);
287 0 : return code;
288 : }
289 :
290 : int
291 1 : vr_message_dump_object(void *arg, unsigned int object_type, void *object)
292 : {
293 : int ret;
294 : struct vr_mproto *proto;
295 : struct vr_mtransport *trans;
296 1 : struct vr_message_dumper *dumper = (struct vr_message_dumper *)arg;
297 :
298 1 : proto = message_h.vm_proto;
299 1 : trans = message_h.vm_trans;
300 1 : if (!proto || !trans)
301 0 : return 0;
302 :
303 1 : ret = proto->mproto_encode(dumper->dump_buffer + dumper->dump_offset,
304 1 : dumper->dump_buf_len - dumper->dump_offset,
305 : object_type, object, VR_MESSAGE_TYPE_RESPONSE);
306 1 : if (ret < 0) {
307 : /* we have more to dump, but we have to exit early */
308 0 : dumper->dump_num_dumped |= VR_MESSAGE_DUMP_INCOMPLETE;
309 0 : return ret;
310 : }
311 :
312 1 : dumper->dump_offset += ret;
313 1 : dumper->dump_num_dumped++;
314 1 : return ret;
315 : }
316 :
317 : void
318 1 : vr_message_dump_exit(void *context, int ret)
319 : {
320 : struct vr_mproto *proto;
321 : struct vr_mtransport *trans;
322 1 : struct vr_message_dumper *dumper = (struct vr_message_dumper *)context;
323 :
324 1 : proto = message_h.vm_proto;
325 1 : trans = message_h.vm_trans;
326 1 : if (!proto || !trans)
327 0 : return;
328 :
329 1 : if (dumper)
330 1 : ret = dumper->dump_num_dumped;
331 :
332 1 : vr_send_response(ret);
333 :
334 1 : if (dumper) {
335 1 : if (!dumper->dump_offset) {
336 0 : if (dumper->dump_buffer)
337 0 : trans->mtrans_free(dumper->dump_buffer);
338 : } else
339 1 : vr_message_queue_response(dumper->dump_buffer,
340 1 : dumper->dump_offset, false);
341 :
342 1 : vr_free(dumper, VR_MESSAGE_DUMP_OBJECT);
343 : }
344 :
345 1 : return;
346 : }
347 :
348 : struct vr_message_dumper *
349 1 : vr_message_dump_init(void *req)
350 : {
351 : char *buf;
352 : struct vr_message_dumper *dumper;
353 : struct vr_mproto *proto;
354 : struct vr_mtransport *trans;
355 :
356 1 : proto = message_h.vm_proto;
357 1 : trans = message_h.vm_trans;
358 1 : if (!proto || !trans)
359 0 : return NULL;
360 :
361 1 : dumper = vr_zalloc(sizeof(*dumper), VR_MESSAGE_DUMP_OBJECT);
362 1 : if (!dumper)
363 0 : return NULL;
364 :
365 1 : buf = trans->mtrans_alloc(VR_MESSAGE_PAGE_SIZE);
366 1 : if (!buf) {
367 0 : vr_free(dumper, VR_MESSAGE_DUMP_OBJECT);
368 0 : return NULL;
369 : }
370 :
371 1 : dumper->dump_buffer = buf;
372 1 : dumper->dump_buf_len = VR_MESSAGE_PAGE_SIZE;
373 1 : dumper->dump_offset = 0;
374 1 : dumper->dump_req = req;
375 :
376 1 : return dumper;
377 : }
378 :
379 : void
380 53 : vr_message_transport_unregister(struct vr_mtransport *trans)
381 : {
382 53 : if (message_h.vm_trans == trans)
383 53 : message_h.vm_trans = NULL;
384 :
385 53 : return;
386 : }
387 :
388 : int
389 53 : vr_message_transport_register(struct vr_mtransport *trans)
390 : {
391 53 : message_h.vm_trans = trans;
392 53 : return 0;
393 : }
394 :
395 : void
396 53 : vr_message_proto_unregister(struct vr_mproto *proto)
397 : {
398 53 : if (message_h.vm_proto == proto)
399 53 : message_h.vm_proto = NULL;
400 :
401 53 : return;
402 : }
403 :
404 : int
405 53 : vr_message_proto_register(struct vr_mproto *proto)
406 : {
407 53 : if (message_h.vm_proto)
408 0 : return -EEXIST;
409 :
410 53 : message_h.vm_proto = proto;
411 53 : return 0;
412 : }
413 :
|