blob: 90d615f60a484bb530e8533271b6dac754335d02 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
47struct serialize_main_header_t;
48struct serialize_stream_t;
49
50typedef void (serialize_data_function_t) (struct serialize_main_header_t * h,
51 struct serialize_stream_t * s);
52
Dave Barachc3799992016-08-15 11:12:27 -040053typedef struct serialize_stream_t
54{
Ed Warnickecb9cada2015-12-08 15:45:58 -070055 /* Current data buffer being serialized/unserialized. */
Dave Barachc3799992016-08-15 11:12:27 -040056 u8 *buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -070057
58 /* Size of buffer in bytes. */
59 u32 n_buffer_bytes;
60
61 /* Current index into buffer. */
62 u32 current_buffer_index;
63
64 /* Overflow buffer for when there is not enough room at the end of
65 buffer to hold serialized/unserialized data. */
Dave Barachc3799992016-08-15 11:12:27 -040066 u8 *overflow_buffer;
Ed Warnickecb9cada2015-12-08 15:45:58 -070067
68 /* Current index in overflow buffer for reads. */
69 u32 current_overflow_index;
70
71 u32 flags;
72#define SERIALIZE_END_OF_STREAM (1 << 0)
73
74 uword data_function_opaque;
75
Dave Barachc3799992016-08-15 11:12:27 -040076 u32 opaque[64 - 4 * sizeof (u32) - 1 * sizeof (uword) -
77 2 * sizeof (void *)];
Ed Warnickecb9cada2015-12-08 15:45:58 -070078} serialize_stream_t;
79
80always_inline void
81serialize_stream_set_end_of_stream (serialize_stream_t * s)
Dave Barachc3799992016-08-15 11:12:27 -040082{
83 s->flags |= SERIALIZE_END_OF_STREAM;
84}
Ed Warnickecb9cada2015-12-08 15:45:58 -070085
86always_inline uword
87serialize_stream_is_end_of_stream (serialize_stream_t * s)
Dave Barachc3799992016-08-15 11:12:27 -040088{
89 return (s->flags & SERIALIZE_END_OF_STREAM) != 0;
90}
Ed Warnickecb9cada2015-12-08 15:45:58 -070091
Dave Barachc3799992016-08-15 11:12:27 -040092typedef struct serialize_main_header_t
93{
Ed Warnickecb9cada2015-12-08 15:45:58 -070094 u32 recursion_level;
95
96 /* Data callback function and opaque data. */
Dave Barachc3799992016-08-15 11:12:27 -040097 serialize_data_function_t *data_function;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99 /* Error if signaled by data function. */
Dave Barachc3799992016-08-15 11:12:27 -0400100 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101
102 /* Exit unwind point if error occurs. */
103 clib_longjmp_t error_longjmp;
104} serialize_main_header_t;
105
106always_inline void
107serialize_error (serialize_main_header_t * m, clib_error_t * error)
Dave Barachc3799992016-08-15 11:12:27 -0400108{
109 clib_longjmp (&m->error_longjmp, pointer_to_uword (error));
110}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111
112#define serialize_error_return(m,args...) \
113 serialize_error (&(m)->header, clib_error_return (0, args))
114
Dave Barachc3799992016-08-15 11:12:27 -0400115void *serialize_read_write_not_inline (serialize_main_header_t * m,
116 serialize_stream_t * s,
117 uword n_bytes, uword flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118
119#define SERIALIZE_FLAG_IS_READ (1 << 0)
120#define SERIALIZE_FLAG_IS_WRITE (1 << 1)
121
122always_inline void *
123serialize_stream_read_write (serialize_main_header_t * header,
124 serialize_stream_t * s,
Dave Barachc3799992016-08-15 11:12:27 -0400125 uword n_bytes, uword flags)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126{
127 uword i, j, l;
128
129 l = vec_len (s->overflow_buffer);
130 i = s->current_buffer_index;
131 j = i + n_bytes;
132 s->current_buffer_index = j;
133 if (l == 0 && j <= s->n_buffer_bytes)
134 {
135 return s->buffer + i;
136 }
137 else
138 {
139 s->current_buffer_index = i;
140 return serialize_read_write_not_inline (header, s, n_bytes, flags);
141 }
142}
143
Dave Barachc3799992016-08-15 11:12:27 -0400144typedef struct
145{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146 serialize_main_header_t header;
147 serialize_stream_t stream;
148} serialize_main_t;
149
150always_inline void
151serialize_set_end_of_stream (serialize_main_t * m)
Dave Barachc3799992016-08-15 11:12:27 -0400152{
153 serialize_stream_set_end_of_stream (&m->stream);
154}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156always_inline uword
157serialize_is_end_of_stream (serialize_main_t * m)
Dave Barachc3799992016-08-15 11:12:27 -0400158{
159 return serialize_stream_is_end_of_stream (&m->stream);
160}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161
Dave Barachc3799992016-08-15 11:12:27 -0400162typedef struct
163{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 serialize_main_header_t header;
Dave Barachc3799992016-08-15 11:12:27 -0400165 serialize_stream_t *streams;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166} serialize_multiple_main_t;
167
168typedef void (serialize_function_t) (serialize_main_t * m, va_list * va);
169
170always_inline void *
171unserialize_get (serialize_main_t * m, uword n_bytes)
Dave Barachc3799992016-08-15 11:12:27 -0400172{
173 return serialize_stream_read_write (&m->header, &m->stream, n_bytes,
174 SERIALIZE_FLAG_IS_READ);
175}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
177always_inline void *
178serialize_get (serialize_main_t * m, uword n_bytes)
Dave Barachc3799992016-08-15 11:12:27 -0400179{
180 return serialize_stream_read_write (&m->header, &m->stream, n_bytes,
181 SERIALIZE_FLAG_IS_WRITE);
182}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183
184always_inline void
185serialize_integer (serialize_main_t * m, u64 x, u32 n_bytes)
186{
Dave Barachc3799992016-08-15 11:12:27 -0400187 u8 *p = serialize_get (m, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188 if (n_bytes == 1)
189 p[0] = x;
190 else if (n_bytes == 2)
191 clib_mem_unaligned (p, u16) = clib_host_to_net_u16 (x);
192 else if (n_bytes == 4)
193 clib_mem_unaligned (p, u32) = clib_host_to_net_u32 (x);
194 else if (n_bytes == 8)
195 clib_mem_unaligned (p, u64) = clib_host_to_net_u64 (x);
196 else
197 ASSERT (0);
198}
199
200always_inline void
Dave Barachc3799992016-08-15 11:12:27 -0400201unserialize_integer (serialize_main_t * m, void *x, u32 n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202{
Dave Barachc3799992016-08-15 11:12:27 -0400203 u8 *p = unserialize_get (m, n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 if (n_bytes == 1)
205 *(u8 *) x = p[0];
206 else if (n_bytes == 2)
207 *(u16 *) x = clib_net_to_host_unaligned_mem_u16 ((u16 *) p);
208 else if (n_bytes == 4)
209 *(u32 *) x = clib_net_to_host_unaligned_mem_u32 ((u32 *) p);
210 else if (n_bytes == 8)
211 *(u64 *) x = clib_net_to_host_unaligned_mem_u64 ((u64 *) p);
212 else
213 ASSERT (0);
214}
215
216/* As above but tries to be more compact. */
217always_inline void
218serialize_likely_small_unsigned_integer (serialize_main_t * m, u64 x)
219{
220 u64 r = x;
Dave Barachc3799992016-08-15 11:12:27 -0400221 u8 *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222
223 /* Low bit set means it fits into 1 byte. */
224 if (r < (1 << 7))
225 {
226 p = serialize_get (m, 1);
Dave Barachc3799992016-08-15 11:12:27 -0400227 p[0] = 1 + 2 * r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 return;
229 }
230
231 /* Low 2 bits 1 0 means it fits into 2 bytes. */
232 r -= (1 << 7);
233 if (r < (1 << 14))
234 {
235 p = serialize_get (m, 2);
236 clib_mem_unaligned (p, u16) = clib_host_to_little_u16 (4 * r + 2);
237 return;
238 }
239
240 r -= (1 << 14);
241 if (r < (1 << 29))
242 {
243 p = serialize_get (m, 4);
244 clib_mem_unaligned (p, u32) = clib_host_to_little_u32 (8 * r + 4);
245 return;
246 }
247
248 p = serialize_get (m, 9);
249 p[0] = 0; /* Only low 3 bits are used. */
250 clib_mem_unaligned (p + 1, u64) = clib_host_to_little_u64 (x);
251}
252
253always_inline u64
254unserialize_likely_small_unsigned_integer (serialize_main_t * m)
255{
Dave Barachc3799992016-08-15 11:12:27 -0400256 u8 *p = unserialize_get (m, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 u64 r;
258 u32 y = p[0];
259
260 if (y & 1)
261 return y / 2;
262
263 r = 1 << 7;
264 if (y & 2)
265 {
266 p = unserialize_get (m, 1);
267 r += (y / 4) + (p[0] << 6);
268 return r;
269 }
270
271 r += 1 << 14;
272 if (y & 4)
273 {
274 p = unserialize_get (m, 3);
275 r += ((y / 8)
Dave Barachc3799992016-08-15 11:12:27 -0400276 + (p[0] << (5 + 8 * 0))
277 + (p[1] << (5 + 8 * 1)) + (p[2] << (5 + 8 * 2)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 return r;
279 }
280
281 p = unserialize_get (m, 8);
282 r = clib_mem_unaligned (p, u64);
283 r = clib_little_to_host_u64 (r);
284
285 return r;
286}
287
288always_inline void
289serialize_likely_small_signed_integer (serialize_main_t * m, i64 s)
290{
Dave Barachc3799992016-08-15 11:12:27 -0400291 u64 u = s < 0 ? -(2 * s + 1) : 2 * s;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 serialize_likely_small_unsigned_integer (m, u);
293}
294
295always_inline i64
296unserialize_likely_small_signed_integer (serialize_main_t * m)
297{
298 u64 u = unserialize_likely_small_unsigned_integer (m);
299 i64 s = u / 2;
300 return (u & 1) ? -s : s;
301}
302
303void
304serialize_multiple_1 (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400305 void *data, uword data_stride, uword n_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306void
307serialize_multiple_2 (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400308 void *data, uword data_stride, uword n_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309void
310serialize_multiple_4 (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400311 void *data, uword data_stride, uword n_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312
313void
314unserialize_multiple_1 (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400315 void *data, uword data_stride, uword n_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316void
317unserialize_multiple_2 (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400318 void *data, uword data_stride, uword n_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319void
320unserialize_multiple_4 (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400321 void *data, uword data_stride, uword n_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322
323always_inline void
324serialize_multiple (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400325 void *data,
326 uword n_data_bytes, uword data_stride, uword n_data)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327{
328 if (n_data_bytes == 1)
329 serialize_multiple_1 (m, data, data_stride, n_data);
330 else if (n_data_bytes == 2)
331 serialize_multiple_2 (m, data, data_stride, n_data);
332 else if (n_data_bytes == 4)
333 serialize_multiple_4 (m, data, data_stride, n_data);
334 else
335 ASSERT (0);
336}
337
338always_inline void
339unserialize_multiple (serialize_main_t * m,
Dave Barachc3799992016-08-15 11:12:27 -0400340 void *data,
341 uword n_data_bytes, uword data_stride, uword n_data)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342{
343 if (n_data_bytes == 1)
344 unserialize_multiple_1 (m, data, data_stride, n_data);
345 else if (n_data_bytes == 2)
346 unserialize_multiple_2 (m, data, data_stride, n_data);
347 else if (n_data_bytes == 4)
348 unserialize_multiple_4 (m, data, data_stride, n_data);
349 else
350 ASSERT (0);
351}
352
353/* Basic types. */
354serialize_function_t serialize_64, unserialize_64;
355serialize_function_t serialize_32, unserialize_32;
356serialize_function_t serialize_16, unserialize_16;
357serialize_function_t serialize_8, unserialize_8;
358serialize_function_t serialize_f64, unserialize_f64;
359serialize_function_t serialize_f32, unserialize_f32;
360
361/* Basic vector types. */
362serialize_function_t serialize_vec_8, unserialize_vec_8;
363serialize_function_t serialize_vec_16, unserialize_vec_16;
364serialize_function_t serialize_vec_32, unserialize_vec_32;
365serialize_function_t serialize_vec_64, unserialize_vec_64;
366
367/* Serialize generic vectors. */
Dave Barachc3799992016-08-15 11:12:27 -0400368serialize_function_t serialize_vector, unserialize_vector,
369 unserialize_aligned_vector;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370
371#define vec_serialize(m,v,f) \
372 serialize ((m), serialize_vector, (v), sizeof ((v)[0]), (f))
373
374#define vec_unserialize(m,v,f) \
375 unserialize ((m), unserialize_vector, (v), sizeof ((*(v))[0]), (f))
376
377#define vec_unserialize_aligned(m,v,f) \
378 unserialize ((m), unserialize_aligned_vector, (v), sizeof ((*(v))[0]), (f))
379
380/* Serialize pools. */
Dave Barachc3799992016-08-15 11:12:27 -0400381serialize_function_t serialize_pool, unserialize_pool,
382 unserialize_aligned_pool;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383
384#define pool_serialize(m,v,f) \
385 serialize ((m), serialize_pool, (v), sizeof ((v)[0]), (f))
386
387#define pool_unserialize(m,v,f) \
388 unserialize ((m), unserialize_pool, (v), sizeof ((*(v))[0]), (f))
389
390#define pool_unserialize_aligned(m,v,a,f) \
391 unserialize ((m), unserialize_aligned_pool, (v), sizeof ((*(v))[0]), (a), (f))
392
393/* Serialize heaps. */
394serialize_function_t serialize_heap, unserialize_heap;
395
396void serialize_bitmap (serialize_main_t * m, uword * b);
Dave Barachc3799992016-08-15 11:12:27 -0400397uword *unserialize_bitmap (serialize_main_t * m);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398
Dave Barachc3799992016-08-15 11:12:27 -0400399void serialize_cstring (serialize_main_t * m, char *string);
400void unserialize_cstring (serialize_main_t * m, char **string);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401
402void serialize_close (serialize_main_t * m);
403void unserialize_close (serialize_main_t * m);
404
Dave Barachc3799992016-08-15 11:12:27 -0400405void serialize_open_data (serialize_main_t * m, u8 * data,
406 uword n_data_bytes);
407void unserialize_open_data (serialize_main_t * m, u8 * data,
408 uword n_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409
410/* Starts serialization with expanding vector as buffer. */
411void serialize_open_vector (serialize_main_t * m, u8 * vector);
412
413/* Serialization is done: returns vector buffer to caller. */
Dave Barachc3799992016-08-15 11:12:27 -0400414void *serialize_close_vector (serialize_main_t * m);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415
416void unserialize_open_vector (serialize_main_t * m, u8 * vector);
417
418#ifdef CLIB_UNIX
Dave Barach59b25652017-09-10 15:04:27 -0400419clib_error_t *serialize_open_clib_file (serialize_main_t * m, char *file);
420clib_error_t *unserialize_open_clib_file (serialize_main_t * m, char *file);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421
Dave Barach59b25652017-09-10 15:04:27 -0400422void serialize_open_clib_file_descriptor (serialize_main_t * m, int fd);
423void unserialize_open_clib_file_descriptor (serialize_main_t * m, int fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424#endif /* CLIB_UNIX */
425
426/* Main routines. */
Dave Barachc3799992016-08-15 11:12:27 -0400427clib_error_t *serialize (serialize_main_t * m, ...);
428clib_error_t *unserialize (serialize_main_t * m, ...);
429clib_error_t *va_serialize (serialize_main_t * m, va_list * va);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
Dave Barachc3799992016-08-15 11:12:27 -0400431void serialize_magic (serialize_main_t * m, void *magic, u32 magic_bytes);
432void unserialize_check_magic (serialize_main_t * m, void *magic,
433 u32 magic_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
435#endif /* included_clib_serialize_h */
Dave Barachc3799992016-08-15 11:12:27 -0400436
437/*
438 * fd.io coding-style-patch-verification: ON
439 *
440 * Local Variables:
441 * eval: (c-set-style "gnu")
442 * End:
443 */