Initial commit of vpp code.
[vpp.git] / vppinfra / vppinfra / serialize.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2005 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #ifndef included_clib_serialize_h
39 #define included_clib_serialize_h
40
41 #include <stdarg.h>
42 #include <vppinfra/byte_order.h>
43 #include <vppinfra/types.h>
44 #include <vppinfra/vec.h>
45 #include <vppinfra/longjmp.h>
46
47 struct serialize_main_header_t;
48 struct serialize_stream_t;
49
50 typedef void (serialize_data_function_t) (struct serialize_main_header_t * h,
51                                           struct serialize_stream_t * s);
52
53 typedef struct serialize_stream_t {
54   /* Current data buffer being serialized/unserialized. */
55   u8 * buffer;
56
57   /* Size of buffer in bytes. */
58   u32 n_buffer_bytes;
59
60   /* Current index into buffer. */
61   u32 current_buffer_index;
62
63   /* Overflow buffer for when there is not enough room at the end of
64      buffer to hold serialized/unserialized data. */
65   u8 * overflow_buffer;
66
67   /* Current index in overflow buffer for reads. */
68   u32 current_overflow_index;
69
70   u32 flags;
71 #define SERIALIZE_END_OF_STREAM (1 << 0)
72
73   uword data_function_opaque;
74
75   u32 opaque[64 - 4 * sizeof (u32) - 1 * sizeof (uword) - 2 * sizeof (void *)];
76 } serialize_stream_t;
77
78 always_inline void
79 serialize_stream_set_end_of_stream (serialize_stream_t * s)
80 { s->flags |= SERIALIZE_END_OF_STREAM; }
81
82 always_inline uword
83 serialize_stream_is_end_of_stream (serialize_stream_t * s)
84 { return (s->flags & SERIALIZE_END_OF_STREAM) != 0; }
85
86 typedef struct serialize_main_header_t {
87   u32 recursion_level;
88
89   /* Data callback function and opaque data. */
90   serialize_data_function_t * data_function;
91
92   /* Error if signaled by data function. */
93   clib_error_t * error;
94
95   /* Exit unwind point if error occurs. */
96   clib_longjmp_t error_longjmp;
97 } serialize_main_header_t;
98
99 always_inline void
100 serialize_error (serialize_main_header_t * m, clib_error_t * error)
101 { clib_longjmp (&m->error_longjmp, pointer_to_uword (error)); }
102
103 #define serialize_error_return(m,args...)                       \
104   serialize_error (&(m)->header, clib_error_return (0, args))
105
106 void * serialize_read_write_not_inline (serialize_main_header_t * m,
107                                         serialize_stream_t * s,
108                                         uword n_bytes, uword flags);
109
110 #define SERIALIZE_FLAG_IS_READ  (1 << 0)
111 #define SERIALIZE_FLAG_IS_WRITE (1 << 1)
112
113 always_inline void *
114 serialize_stream_read_write (serialize_main_header_t * header,
115                              serialize_stream_t * s,
116                              uword n_bytes,
117                              uword flags)
118 {
119   uword i, j, l;
120
121   l = vec_len (s->overflow_buffer);
122   i = s->current_buffer_index;
123   j = i + n_bytes;
124   s->current_buffer_index = j;
125   if (l == 0 && j <= s->n_buffer_bytes)
126     {
127       return s->buffer + i;
128     }
129   else
130     {
131       s->current_buffer_index = i;
132       return serialize_read_write_not_inline (header, s, n_bytes, flags);
133     }
134 }
135
136 typedef struct {
137   serialize_main_header_t header;
138   serialize_stream_t stream;
139 } serialize_main_t;
140
141 always_inline void
142 serialize_set_end_of_stream (serialize_main_t * m)
143 { serialize_stream_set_end_of_stream (&m->stream); }
144
145 always_inline uword
146 serialize_is_end_of_stream (serialize_main_t * m)
147 { return serialize_stream_is_end_of_stream (&m->stream); }
148
149 typedef struct {
150   serialize_main_header_t header;
151   serialize_stream_t * streams;
152 } serialize_multiple_main_t;
153
154 typedef void (serialize_function_t) (serialize_main_t * m, va_list * va);
155
156 always_inline void *
157 unserialize_get (serialize_main_t * m, uword n_bytes)
158 { return serialize_stream_read_write (&m->header, &m->stream, n_bytes, SERIALIZE_FLAG_IS_READ); }
159
160 always_inline void *
161 serialize_get (serialize_main_t * m, uword n_bytes)
162 { return serialize_stream_read_write (&m->header, &m->stream, n_bytes, SERIALIZE_FLAG_IS_WRITE); }
163
164 always_inline void
165 serialize_integer (serialize_main_t * m, u64 x, u32 n_bytes)
166 {
167   u8 * p = serialize_get (m, n_bytes);
168   if (n_bytes == 1)
169     p[0] = x;
170   else if (n_bytes == 2)
171     clib_mem_unaligned (p, u16) = clib_host_to_net_u16 (x);
172   else if (n_bytes == 4)
173     clib_mem_unaligned (p, u32) = clib_host_to_net_u32 (x);
174   else if (n_bytes == 8)
175     clib_mem_unaligned (p, u64) = clib_host_to_net_u64 (x);
176   else
177     ASSERT (0);
178 }
179
180 always_inline void
181 unserialize_integer (serialize_main_t * m, void * x, u32 n_bytes)
182 {
183   u8 * p = unserialize_get (m, n_bytes);
184   if (n_bytes == 1)
185     *(u8 *) x = p[0];
186   else if (n_bytes == 2)
187     *(u16 *) x = clib_net_to_host_unaligned_mem_u16 ((u16 *) p);
188   else if (n_bytes == 4)
189     *(u32 *) x = clib_net_to_host_unaligned_mem_u32 ((u32 *) p);
190   else if (n_bytes == 8)
191     *(u64 *) x = clib_net_to_host_unaligned_mem_u64 ((u64 *) p);
192   else
193     ASSERT (0);
194 }
195
196 /* As above but tries to be more compact. */
197 always_inline void
198 serialize_likely_small_unsigned_integer (serialize_main_t * m, u64 x)
199 {
200   u64 r = x;
201   u8 * p;
202
203   /* Low bit set means it fits into 1 byte. */
204   if (r < (1 << 7))
205     {
206       p = serialize_get (m, 1);
207       p[0] = 1 + 2*r;
208       return;
209     }
210
211   /* Low 2 bits 1 0 means it fits into 2 bytes. */
212   r -= (1 << 7);
213   if (r < (1 << 14))
214     {
215       p = serialize_get (m, 2);
216       clib_mem_unaligned (p, u16) = clib_host_to_little_u16 (4 * r + 2);
217       return;
218     }
219
220   r -= (1 << 14);
221   if (r < (1 << 29))
222     {
223       p = serialize_get (m, 4);
224       clib_mem_unaligned (p, u32) = clib_host_to_little_u32 (8 * r + 4);
225       return;
226     }
227
228   p = serialize_get (m, 9);
229   p[0] = 0;                     /* Only low 3 bits are used. */
230   clib_mem_unaligned (p + 1, u64) = clib_host_to_little_u64 (x);
231 }
232
233 always_inline u64
234 unserialize_likely_small_unsigned_integer (serialize_main_t * m)
235 {
236   u8 * p = unserialize_get (m, 1);
237   u64 r;
238   u32 y = p[0];
239
240   if (y & 1)
241     return y / 2;
242
243   r = 1 << 7;
244   if (y & 2)
245     {
246       p = unserialize_get (m, 1);
247       r += (y / 4) + (p[0] << 6);
248       return r;
249     }
250
251   r += 1 << 14;
252   if (y & 4)
253     {
254       p = unserialize_get (m, 3);
255       r += ((y / 8)
256             + (p[0] << (5 + 8*0))
257             + (p[1] << (5 + 8*1))
258             + (p[2] << (5 + 8*2)));
259       return r;
260     }
261
262   p = unserialize_get (m, 8);
263   r = clib_mem_unaligned (p, u64);
264   r = clib_little_to_host_u64 (r);
265
266   return r;
267 }
268
269 always_inline void
270 serialize_likely_small_signed_integer (serialize_main_t * m, i64 s)
271 {
272   u64 u = s < 0 ? -(2*s + 1) : 2*s;
273   serialize_likely_small_unsigned_integer (m, u);
274 }
275
276 always_inline i64
277 unserialize_likely_small_signed_integer (serialize_main_t * m)
278 {
279   u64 u = unserialize_likely_small_unsigned_integer (m);
280   i64 s = u / 2;
281   return (u & 1) ? -s : s;
282 }
283
284 void
285 serialize_multiple_1 (serialize_main_t * m,
286                       void * data,
287                       uword data_stride,
288                       uword n_data);
289 void
290 serialize_multiple_2 (serialize_main_t * m,
291                       void * data,
292                       uword data_stride,
293                       uword n_data);
294 void
295 serialize_multiple_4 (serialize_main_t * m,
296                       void * data,
297                       uword data_stride,
298                       uword n_data);
299
300 void
301 unserialize_multiple_1 (serialize_main_t * m,
302                         void * data,
303                         uword data_stride,
304                         uword n_data);
305 void
306 unserialize_multiple_2 (serialize_main_t * m,
307                         void * data,
308                         uword data_stride,
309                         uword n_data);
310 void
311 unserialize_multiple_4 (serialize_main_t * m,
312                         void * data,
313                         uword data_stride,
314                         uword n_data);
315
316 always_inline void
317 serialize_multiple (serialize_main_t * m,
318                     void * data,
319                     uword n_data_bytes,
320                     uword data_stride,
321                     uword n_data)
322 {
323   if (n_data_bytes == 1)
324     serialize_multiple_1 (m, data, data_stride, n_data);
325   else if (n_data_bytes == 2)
326     serialize_multiple_2 (m, data, data_stride, n_data);
327   else if (n_data_bytes == 4)
328     serialize_multiple_4 (m, data, data_stride, n_data);
329   else
330     ASSERT (0);
331 }
332
333 always_inline void
334 unserialize_multiple (serialize_main_t * m,
335                       void * data,
336                       uword n_data_bytes,
337                       uword data_stride,
338                       uword n_data)
339 {
340   if (n_data_bytes == 1)
341     unserialize_multiple_1 (m, data, data_stride, n_data);
342   else if (n_data_bytes == 2)
343     unserialize_multiple_2 (m, data, data_stride, n_data);
344   else if (n_data_bytes == 4)
345     unserialize_multiple_4 (m, data, data_stride, n_data);
346   else
347     ASSERT (0);
348 }
349
350 /* Basic types. */
351 serialize_function_t serialize_64, unserialize_64;
352 serialize_function_t serialize_32, unserialize_32;
353 serialize_function_t serialize_16, unserialize_16;
354 serialize_function_t serialize_8, unserialize_8;
355 serialize_function_t serialize_f64, unserialize_f64;
356 serialize_function_t serialize_f32, unserialize_f32;
357
358 /* Basic vector types. */
359 serialize_function_t serialize_vec_8, unserialize_vec_8;
360 serialize_function_t serialize_vec_16, unserialize_vec_16;
361 serialize_function_t serialize_vec_32, unserialize_vec_32;
362 serialize_function_t serialize_vec_64, unserialize_vec_64;
363
364 /* Serialize generic vectors. */
365 serialize_function_t serialize_vector, unserialize_vector, unserialize_aligned_vector;
366
367 #define vec_serialize(m,v,f) \
368   serialize ((m), serialize_vector, (v), sizeof ((v)[0]), (f))
369
370 #define vec_unserialize(m,v,f) \
371   unserialize ((m), unserialize_vector, (v), sizeof ((*(v))[0]), (f))
372
373 #define vec_unserialize_aligned(m,v,f) \
374   unserialize ((m), unserialize_aligned_vector, (v), sizeof ((*(v))[0]), (f))
375
376 /* Serialize pools. */
377 serialize_function_t serialize_pool, unserialize_pool, unserialize_aligned_pool;
378
379 #define pool_serialize(m,v,f) \
380   serialize ((m), serialize_pool, (v), sizeof ((v)[0]), (f))
381
382 #define pool_unserialize(m,v,f) \
383   unserialize ((m), unserialize_pool, (v), sizeof ((*(v))[0]), (f))
384
385 #define pool_unserialize_aligned(m,v,a,f)                               \
386   unserialize ((m), unserialize_aligned_pool, (v), sizeof ((*(v))[0]), (a), (f))
387
388 /* Serialize heaps. */
389 serialize_function_t serialize_heap, unserialize_heap;
390
391 void serialize_bitmap (serialize_main_t * m, uword * b);
392 uword * unserialize_bitmap (serialize_main_t * m);
393
394 void serialize_cstring (serialize_main_t * m, char * string);
395 void unserialize_cstring (serialize_main_t * m, char ** string);
396
397 void serialize_close (serialize_main_t * m);
398 void unserialize_close (serialize_main_t * m);
399
400 void serialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes);
401 void unserialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes);
402
403 /* Starts serialization with expanding vector as buffer. */
404 void serialize_open_vector (serialize_main_t * m, u8 * vector);
405
406 /* Serialization is done: returns vector buffer to caller. */
407 void * serialize_close_vector (serialize_main_t * m);
408
409 void unserialize_open_vector (serialize_main_t * m, u8 * vector);
410
411 #ifdef CLIB_UNIX
412 clib_error_t * serialize_open_unix_file (serialize_main_t * m, char * file);
413 clib_error_t * unserialize_open_unix_file (serialize_main_t * m, char * file);
414
415 void serialize_open_unix_file_descriptor (serialize_main_t * m, int fd);
416 void unserialize_open_unix_file_descriptor (serialize_main_t * m, int fd);
417 #endif /* CLIB_UNIX */
418
419 /* Main routines. */
420 clib_error_t * serialize (serialize_main_t * m, ...);
421 clib_error_t * unserialize (serialize_main_t * m, ...);
422 clib_error_t * va_serialize (serialize_main_t * m, va_list * va);
423
424 void serialize_magic (serialize_main_t * m, void * magic, u32 magic_bytes);
425 void unserialize_check_magic (serialize_main_t * m, void * magic, u32 magic_bytes);
426
427 #endif /* included_clib_serialize_h */