Line data Source code
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 : {
55 : /* Current data buffer being serialized/unserialized. */
56 : u8 *buffer;
57 :
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. */
66 : u8 *overflow_buffer;
67 :
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 :
76 : u32 opaque[64 - 4 * sizeof (u32) - 1 * sizeof (uword) -
77 : 2 * sizeof (void *)];
78 : } serialize_stream_t;
79 :
80 : always_inline void
81 1631 : serialize_stream_set_end_of_stream (serialize_stream_t * s)
82 : {
83 1631 : s->flags |= SERIALIZE_END_OF_STREAM;
84 1631 : }
85 :
86 : always_inline uword
87 21203 : serialize_stream_is_end_of_stream (serialize_stream_t * s)
88 : {
89 21203 : return (s->flags & SERIALIZE_END_OF_STREAM) != 0;
90 : }
91 :
92 : typedef struct serialize_main_header_t
93 : {
94 : u32 recursion_level;
95 :
96 : /* Data callback function and opaque data. */
97 : serialize_data_function_t *data_function;
98 :
99 : /* Error if signaled by data function. */
100 : clib_error_t *error;
101 :
102 : /* Exit unwind point if error occurs. */
103 : clib_longjmp_t error_longjmp;
104 : } serialize_main_header_t;
105 :
106 : always_inline void
107 0 : serialize_error (serialize_main_header_t * m, clib_error_t * error)
108 : {
109 0 : clib_longjmp (&m->error_longjmp, pointer_to_uword (error));
110 0 : }
111 :
112 : #define serialize_error_return(m,args...) \
113 : serialize_error (&(m)->header, clib_error_return (0, args))
114 :
115 : void *serialize_read_write_not_inline (serialize_main_header_t * m,
116 : serialize_stream_t * s,
117 : uword n_bytes, uword flags);
118 :
119 : #define SERIALIZE_FLAG_IS_READ (1 << 0)
120 : #define SERIALIZE_FLAG_IS_WRITE (1 << 1)
121 :
122 : always_inline void *
123 8841872 : serialize_stream_read_write (serialize_main_header_t * header,
124 : serialize_stream_t * s,
125 : uword n_bytes, uword flags)
126 : {
127 : uword i, j, l;
128 :
129 8841872 : l = vec_len (s->overflow_buffer);
130 8841872 : i = s->current_buffer_index;
131 8841872 : j = i + n_bytes;
132 8841872 : s->current_buffer_index = j;
133 8841872 : if (l == 0 && j <= s->n_buffer_bytes)
134 : {
135 8810882 : return s->buffer + i;
136 : }
137 : else
138 : {
139 30986 : s->current_buffer_index = i;
140 30986 : return serialize_read_write_not_inline (header, s, n_bytes, flags);
141 : }
142 : }
143 :
144 : typedef struct
145 : {
146 : serialize_main_header_t header;
147 : serialize_stream_t stream;
148 : } serialize_main_t;
149 :
150 : always_inline void
151 : serialize_set_end_of_stream (serialize_main_t * m)
152 : {
153 : serialize_stream_set_end_of_stream (&m->stream);
154 : }
155 :
156 : always_inline uword
157 : serialize_is_end_of_stream (serialize_main_t * m)
158 : {
159 : return serialize_stream_is_end_of_stream (&m->stream);
160 : }
161 :
162 : typedef struct
163 : {
164 : serialize_main_header_t header;
165 : serialize_stream_t *streams;
166 : } serialize_multiple_main_t;
167 :
168 : typedef void (serialize_function_t) (serialize_main_t * m, va_list * va);
169 :
170 : always_inline void *
171 321386 : unserialize_get (serialize_main_t * m, uword n_bytes)
172 : {
173 321386 : return serialize_stream_read_write (&m->header, &m->stream, n_bytes,
174 : SERIALIZE_FLAG_IS_READ);
175 : }
176 :
177 : always_inline void *
178 8520480 : serialize_get (serialize_main_t * m, uword n_bytes)
179 : {
180 8520480 : return serialize_stream_read_write (&m->header, &m->stream, n_bytes,
181 : SERIALIZE_FLAG_IS_WRITE);
182 : }
183 :
184 : always_inline void
185 1631 : serialize_integer (serialize_main_t * m, u64 x, u32 n_bytes)
186 : {
187 1631 : u8 *p = serialize_get (m, n_bytes);
188 1631 : if (n_bytes == 1)
189 0 : p[0] = x;
190 1631 : else if (n_bytes == 2)
191 0 : clib_mem_unaligned (p, u16) = clib_host_to_net_u16 (x);
192 1631 : else if (n_bytes == 4)
193 1631 : clib_mem_unaligned (p, u32) = clib_host_to_net_u32 (x);
194 0 : else if (n_bytes == 8)
195 0 : clib_mem_unaligned (p, u64) = clib_host_to_net_u64 (x);
196 : else
197 0 : ASSERT (0);
198 1631 : }
199 :
200 : always_inline void
201 47 : unserialize_integer (serialize_main_t * m, void *x, u32 n_bytes)
202 : {
203 47 : u8 *p = unserialize_get (m, n_bytes);
204 47 : if (n_bytes == 1)
205 0 : *(u8 *) x = p[0];
206 47 : else if (n_bytes == 2)
207 0 : *(u16 *) x = clib_net_to_host_unaligned_mem_u16 ((u16 *) p);
208 47 : else if (n_bytes == 4)
209 47 : *(u32 *) x = clib_net_to_host_unaligned_mem_u32 ((u32 *) p);
210 0 : else if (n_bytes == 8)
211 0 : *(u64 *) x = clib_net_to_host_unaligned_mem_u64 ((u64 *) p);
212 : else
213 0 : ASSERT (0);
214 47 : }
215 :
216 : /* As above but tries to be more compact. */
217 : always_inline void
218 5679240 : serialize_likely_small_unsigned_integer (serialize_main_t * m, u64 x)
219 : {
220 5679240 : u64 r = x;
221 : u8 *p;
222 :
223 : /* Low bit set means it fits into 1 byte. */
224 5679240 : if (r < (1 << 7))
225 : {
226 3046757 : p = serialize_get (m, 1);
227 3046757 : p[0] = 1 + 2 * r;
228 3046757 : return;
229 : }
230 :
231 : /* Low 2 bits 1 0 means it fits into 2 bytes. */
232 2632480 : r -= (1 << 7);
233 2632480 : if (r < (1 << 14))
234 : {
235 2632480 : p = serialize_get (m, 2);
236 2632480 : clib_mem_unaligned (p, u16) = clib_host_to_little_u16 (4 * r + 2);
237 2632480 : return;
238 : }
239 :
240 0 : r -= (1 << 14);
241 0 : if (r < (1 << 29))
242 : {
243 0 : p = serialize_get (m, 4);
244 0 : clib_mem_unaligned (p, u32) = clib_host_to_little_u32 (8 * r + 4);
245 0 : return;
246 : }
247 :
248 0 : p = serialize_get (m, 9);
249 0 : p[0] = 0; /* Only low 3 bits are used. */
250 0 : clib_mem_unaligned (p + 1, u64) = clib_host_to_little_u64 (x);
251 : }
252 :
253 : always_inline u64
254 163654 : unserialize_likely_small_unsigned_integer (serialize_main_t * m)
255 : {
256 163654 : u8 *p = unserialize_get (m, 1);
257 : u64 r;
258 163654 : u32 y = p[0];
259 :
260 163654 : if (y & 1)
261 87796 : return y / 2;
262 :
263 75858 : r = 1 << 7;
264 75858 : if (y & 2)
265 : {
266 75858 : p = unserialize_get (m, 1);
267 75858 : r += (y / 4) + (p[0] << 6);
268 75858 : return r;
269 : }
270 :
271 0 : r += 1 << 14;
272 0 : if (y & 4)
273 : {
274 0 : p = unserialize_get (m, 3);
275 0 : r += ((y / 8)
276 0 : + (p[0] << (5 + 8 * 0))
277 0 : + (p[1] << (5 + 8 * 1)) + (p[2] << (5 + 8 * 2)));
278 0 : return r;
279 : }
280 :
281 0 : p = unserialize_get (m, 8);
282 0 : r = clib_mem_unaligned (p, u64);
283 0 : r = clib_little_to_host_u64 (r);
284 :
285 0 : return r;
286 : }
287 :
288 : always_inline void
289 : serialize_likely_small_signed_integer (serialize_main_t * m, i64 s)
290 : {
291 : u64 u = s < 0 ? -(2 * s + 1) : 2 * s;
292 : serialize_likely_small_unsigned_integer (m, u);
293 : }
294 :
295 : always_inline i64
296 : unserialize_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 :
303 : void
304 : serialize_multiple_1 (serialize_main_t * m,
305 : void *data, uword data_stride, uword n_data);
306 : void
307 : serialize_multiple_2 (serialize_main_t * m,
308 : void *data, uword data_stride, uword n_data);
309 : void
310 : serialize_multiple_4 (serialize_main_t * m,
311 : void *data, uword data_stride, uword n_data);
312 :
313 : void
314 : unserialize_multiple_1 (serialize_main_t * m,
315 : void *data, uword data_stride, uword n_data);
316 : void
317 : unserialize_multiple_2 (serialize_main_t * m,
318 : void *data, uword data_stride, uword n_data);
319 : void
320 : unserialize_multiple_4 (serialize_main_t * m,
321 : void *data, uword data_stride, uword n_data);
322 :
323 : always_inline void
324 : serialize_multiple (serialize_main_t * m,
325 : void *data,
326 : uword n_data_bytes, uword data_stride, uword n_data)
327 : {
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 :
338 : always_inline void
339 : unserialize_multiple (serialize_main_t * m,
340 : void *data,
341 : uword n_data_bytes, uword data_stride, uword n_data)
342 : {
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. */
354 : serialize_function_t serialize_64, unserialize_64;
355 : serialize_function_t serialize_32, unserialize_32;
356 : serialize_function_t serialize_16, unserialize_16;
357 : serialize_function_t serialize_8, unserialize_8;
358 : serialize_function_t serialize_f64, unserialize_f64;
359 : serialize_function_t serialize_f32, unserialize_f32;
360 :
361 : /* Basic vector types. */
362 : serialize_function_t serialize_vec_8, unserialize_vec_8;
363 : serialize_function_t serialize_vec_16, unserialize_vec_16;
364 : serialize_function_t serialize_vec_32, unserialize_vec_32;
365 : serialize_function_t serialize_vec_64, unserialize_vec_64;
366 :
367 : /* Serialize generic vectors. */
368 : serialize_function_t serialize_vector, unserialize_vector,
369 : unserialize_aligned_vector;
370 :
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. */
381 : serialize_function_t serialize_pool, unserialize_pool,
382 : unserialize_aligned_pool;
383 :
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. */
394 : serialize_function_t serialize_heap, unserialize_heap;
395 :
396 : void serialize_bitmap (serialize_main_t * m, uword * b);
397 : uword *unserialize_bitmap (serialize_main_t * m);
398 :
399 : void serialize_cstring (serialize_main_t * m, char *string);
400 : void unserialize_cstring (serialize_main_t * m, char **string);
401 :
402 : void serialize_close (serialize_main_t * m);
403 : void unserialize_close (serialize_main_t * m);
404 :
405 : void serialize_open_data (serialize_main_t * m, u8 * data,
406 : uword n_data_bytes);
407 : void unserialize_open_data (serialize_main_t * m, u8 * data,
408 : uword n_data_bytes);
409 :
410 : /* Starts serialization with expanding vector as buffer. */
411 : void serialize_open_vector (serialize_main_t * m, u8 * vector);
412 :
413 : /* Serialization is done: returns vector buffer to caller. */
414 : void *serialize_close_vector (serialize_main_t * m);
415 :
416 : void unserialize_open_vector (serialize_main_t * m, u8 * vector);
417 :
418 : #ifdef CLIB_UNIX
419 : clib_error_t *serialize_open_clib_file (serialize_main_t * m, char *file);
420 : clib_error_t *unserialize_open_clib_file (serialize_main_t * m, char *file);
421 :
422 : void serialize_open_clib_file_descriptor (serialize_main_t * m, int fd);
423 : void unserialize_open_clib_file_descriptor (serialize_main_t * m, int fd);
424 : #endif /* CLIB_UNIX */
425 :
426 : /* Main routines. */
427 : clib_error_t *serialize (serialize_main_t * m, ...);
428 : clib_error_t *unserialize (serialize_main_t * m, ...);
429 : clib_error_t *va_serialize (serialize_main_t * m, va_list * va);
430 :
431 : void serialize_magic (serialize_main_t * m, void *magic, u32 magic_bytes);
432 : void unserialize_check_magic (serialize_main_t * m, void *magic,
433 : u32 magic_bytes);
434 :
435 : #endif /* included_clib_serialize_h */
436 :
437 : /*
438 : * fd.io coding-style-patch-verification: ON
439 : *
440 : * Local Variables:
441 : * eval: (c-set-style "gnu")
442 : * End:
443 : */
|