dpdk: Add support for Mellanox ConnectX-4 devices
[vpp.git] / src / 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 {
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 serialize_stream_set_end_of_stream (serialize_stream_t * s)
82 {
83   s->flags |= SERIALIZE_END_OF_STREAM;
84 }
85
86 always_inline uword
87 serialize_stream_is_end_of_stream (serialize_stream_t * s)
88 {
89   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 serialize_error (serialize_main_header_t * m, clib_error_t * error)
108 {
109   clib_longjmp (&m->error_longjmp, pointer_to_uword (error));
110 }
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 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   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
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 unserialize_get (serialize_main_t * m, uword n_bytes)
172 {
173   return serialize_stream_read_write (&m->header, &m->stream, n_bytes,
174                                       SERIALIZE_FLAG_IS_READ);
175 }
176
177 always_inline void *
178 serialize_get (serialize_main_t * m, uword n_bytes)
179 {
180   return serialize_stream_read_write (&m->header, &m->stream, n_bytes,
181                                       SERIALIZE_FLAG_IS_WRITE);
182 }
183
184 always_inline void
185 serialize_integer (serialize_main_t * m, u64 x, u32 n_bytes)
186 {
187   u8 *p = serialize_get (m, n_bytes);
188   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
200 always_inline void
201 unserialize_integer (serialize_main_t * m, void *x, u32 n_bytes)
202 {
203   u8 *p = unserialize_get (m, n_bytes);
204   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. */
217 always_inline void
218 serialize_likely_small_unsigned_integer (serialize_main_t * m, u64 x)
219 {
220   u64 r = x;
221   u8 *p;
222
223   /* Low bit set means it fits into 1 byte. */
224   if (r < (1 << 7))
225     {
226       p = serialize_get (m, 1);
227       p[0] = 1 + 2 * r;
228       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
253 always_inline u64
254 unserialize_likely_small_unsigned_integer (serialize_main_t * m)
255 {
256   u8 *p = unserialize_get (m, 1);
257   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)
276             + (p[0] << (5 + 8 * 0))
277             + (p[1] << (5 + 8 * 1)) + (p[2] << (5 + 8 * 2)));
278       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
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_unix_file (serialize_main_t * m, char *file);
420 clib_error_t *unserialize_open_unix_file (serialize_main_t * m, char *file);
421
422 void serialize_open_unix_file_descriptor (serialize_main_t * m, int fd);
423 void unserialize_open_unix_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  */