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