vlib: clean up r2 plugin registration relocator
[vpp.git] / src / vppinfra / serialize.c
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 /* Turn data structures into byte streams for saving or transport. */
39
40 #include <vppinfra/heap.h>
41 #include <vppinfra/pool.h>
42 #include <vppinfra/serialize.h>
43
44 void
45 serialize_64 (serialize_main_t * m, va_list * va)
46 {
47   u64 x = va_arg (*va, u64);
48   u32 lo, hi;
49   lo = x;
50   hi = x >> 32;
51   serialize_integer (m, lo, sizeof (lo));
52   serialize_integer (m, hi, sizeof (hi));
53 }
54
55 void
56 serialize_32 (serialize_main_t * m, va_list * va)
57 {
58   u32 x = va_arg (*va, u32);
59   serialize_integer (m, x, sizeof (x));
60 }
61
62 void
63 serialize_16 (serialize_main_t * m, va_list * va)
64 {
65   u32 x = va_arg (*va, u32);
66   serialize_integer (m, x, sizeof (u16));
67 }
68
69 void
70 serialize_8 (serialize_main_t * m, va_list * va)
71 {
72   u32 x = va_arg (*va, u32);
73   serialize_integer (m, x, sizeof (u8));
74 }
75
76 void
77 unserialize_64 (serialize_main_t * m, va_list * va)
78 {
79   u64 *x = va_arg (*va, u64 *);
80   u32 lo, hi;
81   unserialize_integer (m, &lo, sizeof (lo));
82   unserialize_integer (m, &hi, sizeof (hi));
83   *x = ((u64) hi << 32) | (u64) lo;
84 }
85
86 void
87 unserialize_32 (serialize_main_t * m, va_list * va)
88 {
89   u32 *x = va_arg (*va, u32 *);
90   unserialize_integer (m, x, sizeof (x[0]));
91 }
92
93 void
94 unserialize_16 (serialize_main_t * m, va_list * va)
95 {
96   u16 *x = va_arg (*va, u16 *);
97   u32 t;
98   unserialize_integer (m, &t, sizeof (x[0]));
99   x[0] = t;
100 }
101
102 void
103 unserialize_8 (serialize_main_t * m, va_list * va)
104 {
105   u8 *x = va_arg (*va, u8 *);
106   u32 t;
107   unserialize_integer (m, &t, sizeof (x[0]));
108   x[0] = t;
109 }
110
111 void
112 serialize_f64 (serialize_main_t * m, va_list * va)
113 {
114   f64 x = va_arg (*va, f64);
115   union
116   {
117     f64 f;
118     u64 i;
119   } y;
120   y.f = x;
121   serialize (m, serialize_64, y.i);
122 }
123
124 void
125 serialize_f32 (serialize_main_t * m, va_list * va)
126 {
127   f32 x = va_arg (*va, f64);
128   union
129   {
130     f32 f;
131     u32 i;
132   } y;
133   y.f = x;
134   serialize_integer (m, y.i, sizeof (y.i));
135 }
136
137 void
138 unserialize_f64 (serialize_main_t * m, va_list * va)
139 {
140   f64 *x = va_arg (*va, f64 *);
141   union
142   {
143     f64 f;
144     u64 i;
145   } y;
146   unserialize (m, unserialize_64, &y.i);
147   *x = y.f;
148 }
149
150 void
151 unserialize_f32 (serialize_main_t * m, va_list * va)
152 {
153   f32 *x = va_arg (*va, f32 *);
154   union
155   {
156     f32 f;
157     u32 i;
158   } y;
159   unserialize_integer (m, &y.i, sizeof (y.i));
160   *x = y.f;
161 }
162
163 __clib_export void
164 serialize_cstring (serialize_main_t * m, char *s)
165 {
166   u32 len = s ? strlen (s) : 0;
167   void *p;
168
169   serialize_likely_small_unsigned_integer (m, len);
170   if (len > 0)
171     {
172       p = serialize_get (m, len);
173       clib_memcpy_fast (p, s, len);
174     }
175 }
176
177 __clib_export void
178 unserialize_cstring (serialize_main_t * m, char **s)
179 {
180   char *p, *r = 0;
181   u32 len;
182
183   len = unserialize_likely_small_unsigned_integer (m);
184
185   /*
186    * Given broken enough data, we could get len = 0xFFFFFFFF.
187    * Add one, it overflows, we call vec_new (char, 0), then
188    * memcpy until we bus error.
189    */
190   if (len > 0 && len != 0xFFFFFFFF)
191     {
192       r = vec_new (char, len + 1);
193       p = unserialize_get (m, len);
194       clib_memcpy_fast (r, p, len);
195
196       /* Null terminate. */
197       r[len] = 0;
198     }
199   *s = r;
200 }
201
202 /* vec_serialize/vec_unserialize helper functions for basic vector types. */
203 void
204 serialize_vec_8 (serialize_main_t * m, va_list * va)
205 {
206   u8 *s = va_arg (*va, u8 *);
207   u32 n = va_arg (*va, u32);
208   u8 *p = serialize_get (m, n * sizeof (u8));
209   clib_memcpy_fast (p, s, n * sizeof (u8));
210 }
211
212 void
213 unserialize_vec_8 (serialize_main_t * m, va_list * va)
214 {
215   u8 *s = va_arg (*va, u8 *);
216   u32 n = va_arg (*va, u32);
217   u8 *p = unserialize_get (m, n);
218   clib_memcpy_fast (s, p, n);
219 }
220
221 #define _(n_bits)                                                       \
222   void serialize_vec_##n_bits (serialize_main_t * m, va_list * va)      \
223   {                                                                     \
224     u##n_bits * s = va_arg (*va, u##n_bits *);                          \
225     u32 n = va_arg (*va, u32);                                          \
226     u##n_bits * p = serialize_get (m, n * sizeof (s[0]));               \
227                                                                         \
228     while (n >= 4)                                                      \
229       {                                                                 \
230         p[0] = clib_host_to_net_u##n_bits (s[0]);                       \
231         p[1] = clib_host_to_net_u##n_bits (s[1]);                       \
232         p[2] = clib_host_to_net_u##n_bits (s[2]);                       \
233         p[3] = clib_host_to_net_u##n_bits (s[3]);                       \
234         s += 4;                                                         \
235         p += 4;                                                         \
236         n -= 4;                                                         \
237       }                                                                 \
238                                                                         \
239     while (n >= 1)                                                      \
240       {                                                                 \
241         p[0] = clib_host_to_net_u##n_bits (s[0]);                       \
242         s += 1;                                                         \
243         p += 1;                                                         \
244         n -= 1;                                                         \
245       }                                                                 \
246   }                                                                     \
247                                                                         \
248   void unserialize_vec_##n_bits (serialize_main_t * m, va_list * va)    \
249   {                                                                     \
250     u##n_bits * s = va_arg (*va, u##n_bits *);                          \
251     u32 n = va_arg (*va, u32);                                          \
252     u##n_bits * p = unserialize_get (m, n * sizeof (s[0]));             \
253                                                                         \
254     while (n >= 4)                                                      \
255       {                                                                 \
256         s[0] = clib_net_to_host_mem_u##n_bits (&p[0]);                  \
257         s[1] = clib_net_to_host_mem_u##n_bits (&p[1]);                  \
258         s[2] = clib_net_to_host_mem_u##n_bits (&p[2]);                  \
259         s[3] = clib_net_to_host_mem_u##n_bits (&p[3]);                  \
260         s += 4;                                                         \
261         p += 4;                                                         \
262         n -= 4;                                                         \
263       }                                                                 \
264                                                                         \
265     while (n >= 1)                                                      \
266       {                                                                 \
267         s[0] = clib_net_to_host_mem_u##n_bits (&p[0]);                  \
268         s += 1;                                                         \
269         p += 1;                                                         \
270         n -= 1;                                                         \
271       }                                                                 \
272   }
273
274 _(16);
275 _(32);
276 _(64);
277
278 #undef _
279
280 #define SERIALIZE_VECTOR_CHUNK_SIZE 64
281
282 __clib_export void
283 serialize_vector (serialize_main_t * m, va_list * va)
284 {
285   void *vec = va_arg (*va, void *);
286   u32 elt_bytes = va_arg (*va, u32);
287   serialize_function_t *f = va_arg (*va, serialize_function_t *);
288   u32 l = vec_len (vec);
289   void *p = vec;
290
291   serialize_integer (m, l, sizeof (l));
292
293   /* Serialize vector in chunks for cache locality. */
294   while (l != 0)
295     {
296       u32 n = clib_min (SERIALIZE_VECTOR_CHUNK_SIZE, l);
297       serialize (m, f, p, n);
298       l -= n;
299       p += SERIALIZE_VECTOR_CHUNK_SIZE * elt_bytes;
300     }
301 }
302
303 void *
304 unserialize_vector_ha (serialize_main_t * m,
305                        u32 elt_bytes,
306                        u32 header_bytes,
307                        u32 align, u32 max_length, serialize_function_t * f)
308 {
309   void *v, *p;
310   u32 l;
311   vec_attr_t va = { .align = align,
312                     .elt_sz = elt_bytes,
313                     .hdr_sz = header_bytes };
314
315   unserialize_integer (m, &l, sizeof (l));
316   if (l > max_length)
317     serialize_error (&m->header,
318                      clib_error_create ("bad vector length %d", l));
319
320   p = v = _vec_alloc_internal (l, &va);
321
322   while (l != 0)
323     {
324       u32 n = clib_min (SERIALIZE_VECTOR_CHUNK_SIZE, l);
325       unserialize (m, f, p, n);
326       l -= n;
327       p += SERIALIZE_VECTOR_CHUNK_SIZE * elt_bytes;
328     }
329   return v;
330 }
331
332 void
333 unserialize_aligned_vector (serialize_main_t * m, va_list * va)
334 {
335   void **vec = va_arg (*va, void **);
336   u32 elt_bytes = va_arg (*va, u32);
337   serialize_function_t *f = va_arg (*va, serialize_function_t *);
338   u32 align = va_arg (*va, u32);
339
340   *vec = unserialize_vector_ha (m, elt_bytes,
341                                 /* header_bytes */ 0,
342                                 /* align */ align,
343                                 /* max_length */ ~0,
344                                 f);
345 }
346
347 __clib_export void
348 unserialize_vector (serialize_main_t * m, va_list * va)
349 {
350   void **vec = va_arg (*va, void **);
351   u32 elt_bytes = va_arg (*va, u32);
352   serialize_function_t *f = va_arg (*va, serialize_function_t *);
353
354   *vec = unserialize_vector_ha (m, elt_bytes,
355                                 /* header_bytes */ 0,
356                                 /* align */ 0,
357                                 /* max_length */ ~0,
358                                 f);
359 }
360
361 void
362 serialize_bitmap (serialize_main_t * m, uword * b)
363 {
364   u32 l, i, n_u32s;
365
366   l = vec_len (b);
367   n_u32s = l * sizeof (b[0]) / sizeof (u32);
368   serialize_integer (m, n_u32s, sizeof (n_u32s));
369
370   /* Send 32 bit words, low-order word first on 64 bit. */
371   for (i = 0; i < l; i++)
372     {
373       serialize_integer (m, b[i], sizeof (u32));
374       if (BITS (uword) == 64)
375         serialize_integer (m, (u64) b[i] >> (u64) 32, sizeof (u32));
376     }
377 }
378
379 uword *
380 unserialize_bitmap (serialize_main_t * m)
381 {
382   uword *b = 0;
383   u32 i, n_u32s;
384
385   unserialize_integer (m, &n_u32s, sizeof (n_u32s));
386   if (n_u32s == 0)
387     return b;
388
389   i = (n_u32s * sizeof (u32) + sizeof (b[0]) - 1) / sizeof (b[0]);
390   vec_resize (b, i);
391   for (i = 0; i < n_u32s; i++)
392     {
393       u32 data;
394       unserialize_integer (m, &data, sizeof (u32));
395
396       /* Low-word is first on 64 bit. */
397       if (BITS (uword) == 64)
398         {
399           if ((i % 2) == 0)
400             b[i / 2] |= (u64) data << (u64) 0;
401           else
402             b[i / 2] |= (u64) data << (u64) 32;
403         }
404       else
405         {
406           b[i] = data;
407         }
408     }
409
410   return b;
411 }
412
413 void
414 serialize_pool (serialize_main_t * m, va_list * va)
415 {
416   void *pool = va_arg (*va, void *);
417   u32 elt_bytes = va_arg (*va, u32);
418   serialize_function_t *f = va_arg (*va, serialize_function_t *);
419   u32 l, lo, hi;
420   pool_header_t *p;
421
422   l = vec_len (pool);
423   serialize_integer (m, l, sizeof (u32));
424   if (l == 0)
425     return;
426   p = pool_header (pool);
427
428   /* No need to send free bitmap.  Need to send index vector
429      to guarantee that unserialized pool will be identical. */
430   vec_serialize (m, p->free_indices, serialize_vec_32);
431
432   pool_foreach_region (lo, hi, pool,
433                        serialize (m, f, pool + lo * elt_bytes, hi - lo));
434 }
435
436 static void *
437 unserialize_pool_helper (serialize_main_t * m,
438                          u32 elt_bytes, u32 align, serialize_function_t * f)
439 {
440   void *v;
441   u32 i, l, lo, hi;
442   pool_header_t *p;
443   vec_attr_t va = { .align = align,
444                     .elt_sz = elt_bytes,
445                     .hdr_sz = sizeof (pool_header_t) };
446
447   unserialize_integer (m, &l, sizeof (l));
448   if (l == 0)
449     {
450       return 0;
451     }
452
453   v = _vec_alloc_internal (l, &va);
454   p = pool_header (v);
455
456   vec_unserialize (m, &p->free_indices, unserialize_vec_32);
457
458   /* Construct free bitmap. */
459   p->free_bitmap = 0;
460   for (i = 0; i < vec_len (p->free_indices); i++)
461     p->free_bitmap = clib_bitmap_ori (p->free_bitmap, p->free_indices[i]);
462
463   pool_foreach_region (lo, hi, v,
464                        unserialize (m, f, v + lo * elt_bytes, hi - lo));
465
466   return v;
467 }
468
469 void
470 unserialize_pool (serialize_main_t * m, va_list * va)
471 {
472   void **result = va_arg (*va, void **);
473   u32 elt_bytes = va_arg (*va, u32);
474   serialize_function_t *f = va_arg (*va, serialize_function_t *);
475   *result = unserialize_pool_helper (m, elt_bytes, /* align */ 0, f);
476 }
477
478 void
479 unserialize_aligned_pool (serialize_main_t * m, va_list * va)
480 {
481   void **result = va_arg (*va, void **);
482   u32 elt_bytes = va_arg (*va, u32);
483   u32 align = va_arg (*va, u32);
484   serialize_function_t *f = va_arg (*va, serialize_function_t *);
485   *result = unserialize_pool_helper (m, elt_bytes, align, f);
486 }
487
488 static void
489 serialize_vec_heap_elt (serialize_main_t * m, va_list * va)
490 {
491   heap_elt_t *e = va_arg (*va, heap_elt_t *);
492   u32 i, n = va_arg (*va, u32);
493   for (i = 0; i < n; i++)
494     {
495       serialize_integer (m, e[i].offset, sizeof (e[i].offset));
496       serialize_integer (m, e[i].next, sizeof (e[i].next));
497       serialize_integer (m, e[i].prev, sizeof (e[i].prev));
498     }
499 }
500
501 static void
502 unserialize_vec_heap_elt (serialize_main_t * m, va_list * va)
503 {
504   heap_elt_t *e = va_arg (*va, heap_elt_t *);
505   u32 i, n = va_arg (*va, u32);
506   for (i = 0; i < n; i++)
507     {
508       unserialize_integer (m, &e[i].offset, sizeof (e[i].offset));
509       unserialize_integer (m, &e[i].next, sizeof (e[i].next));
510       unserialize_integer (m, &e[i].prev, sizeof (e[i].prev));
511     }
512 }
513
514 void
515 serialize_heap (serialize_main_t * m, va_list * va)
516 {
517   void *heap = va_arg (*va, void *);
518   serialize_function_t *f = va_arg (*va, serialize_function_t *);
519   u32 i, l;
520   heap_header_t *h;
521
522   l = vec_len (heap);
523   serialize_integer (m, l, sizeof (u32));
524   if (l == 0)
525     return;
526
527   h = heap_header (heap);
528
529 #define foreach_serialize_heap_header_integer \
530   _ (head) _ (tail) _ (used_count) _ (max_len) _ (flags) _ (elt_bytes)
531
532 #define _(f) serialize_integer (m, h->f, sizeof (h->f));
533   foreach_serialize_heap_header_integer;
534 #undef _
535
536   serialize_integer (m, vec_len (h->free_lists), sizeof (u32));
537   for (i = 0; i < vec_len (h->free_lists); i++)
538     vec_serialize (m, h->free_lists[i], serialize_vec_32);
539
540   vec_serialize (m, h->elts, serialize_vec_heap_elt);
541   vec_serialize (m, h->small_free_elt_free_index, serialize_vec_32);
542   vec_serialize (m, h->free_elts, serialize_vec_32);
543
544   /* Serialize data in heap. */
545   {
546     heap_elt_t *e, *end;
547     e = h->elts + h->head;
548     end = h->elts + h->tail;
549     while (1)
550       {
551         if (!heap_is_free (e))
552           {
553             void *v = heap + heap_offset (e) * h->elt_bytes;
554             u32 n = heap_elt_size (heap, e);
555             serialize (m, f, v, n);
556           }
557         if (e == end)
558           break;
559         e = heap_next (e);
560       }
561   }
562 }
563
564 void
565 unserialize_heap (serialize_main_t * m, va_list * va)
566 {
567   void **result = va_arg (*va, void **);
568   serialize_function_t *f = va_arg (*va, serialize_function_t *);
569   u32 i, vl, fl;
570   heap_header_t h;
571   void *heap;
572
573   unserialize_integer (m, &vl, sizeof (u32));
574   if (vl == 0)
575     {
576       *result = 0;
577       return;
578     }
579
580   clib_memset (&h, 0, sizeof (h));
581 #define _(f) unserialize_integer (m, &h.f, sizeof (h.f));
582   foreach_serialize_heap_header_integer;
583 #undef _
584
585   unserialize_integer (m, &fl, sizeof (u32));
586   vec_resize (h.free_lists, fl);
587
588   for (i = 0; i < vec_len (h.free_lists); i++)
589     vec_unserialize (m, &h.free_lists[i], unserialize_vec_32);
590
591   vec_unserialize (m, &h.elts, unserialize_vec_heap_elt);
592   vec_unserialize (m, &h.small_free_elt_free_index, unserialize_vec_32);
593   vec_unserialize (m, &h.free_elts, unserialize_vec_32);
594
595   /* Re-construct used elt bitmap. */
596   if (CLIB_DEBUG > 0)
597     {
598       heap_elt_t *e;
599       vec_foreach (e, h.elts)
600       {
601         if (!heap_is_free (e))
602           h.used_elt_bitmap = clib_bitmap_ori (h.used_elt_bitmap, e - h.elts);
603       }
604     }
605
606   heap = *result = _heap_new (vl, h.elt_bytes);
607   heap_header (heap)[0] = h;
608
609   /* Unserialize data in heap. */
610   {
611     heap_elt_t *e, *end;
612     e = h.elts + h.head;
613     end = h.elts + h.tail;
614     while (1)
615       {
616         if (!heap_is_free (e))
617           {
618             void *v = heap + heap_offset (e) * h.elt_bytes;
619             u32 n = heap_elt_size (heap, e);
620             unserialize (m, f, v, n);
621           }
622         if (e == end)
623           break;
624         e = heap_next (e);
625       }
626   }
627 }
628
629 void
630 serialize_magic (serialize_main_t * m, void *magic, u32 magic_bytes)
631 {
632   void *p;
633   serialize_integer (m, magic_bytes, sizeof (magic_bytes));
634   p = serialize_get (m, magic_bytes);
635   clib_memcpy_fast (p, magic, magic_bytes);
636 }
637
638 void
639 unserialize_check_magic (serialize_main_t * m, void *magic, u32 magic_bytes)
640 {
641   u32 l;
642   void *d;
643
644   unserialize_integer (m, &l, sizeof (l));
645   if (l != magic_bytes)
646     {
647     bad:
648       serialize_error_return (m, "bad magic number");
649     }
650   d = serialize_get (m, magic_bytes);
651   if (memcmp (magic, d, magic_bytes))
652     goto bad;
653 }
654
655 __clib_export clib_error_t *
656 va_serialize (serialize_main_t * sm, va_list * va)
657 {
658   serialize_main_header_t *m = &sm->header;
659   serialize_function_t *f = va_arg (*va, serialize_function_t *);
660   clib_error_t *error = 0;
661
662   m->recursion_level += 1;
663   if (m->recursion_level == 1)
664     {
665       uword r = clib_setjmp (&m->error_longjmp, 0);
666       error = uword_to_pointer (r, clib_error_t *);
667     }
668
669   if (!error)
670     f (sm, va);
671
672   m->recursion_level -= 1;
673   return error;
674 }
675
676 __clib_export clib_error_t *
677 serialize (serialize_main_t * m, ...)
678 {
679   clib_error_t *error;
680   va_list va;
681
682   va_start (va, m);
683   error = va_serialize (m, &va);
684   va_end (va);
685   return error;
686 }
687
688 __clib_export clib_error_t *
689 unserialize (serialize_main_t * m, ...)
690 {
691   clib_error_t *error;
692   va_list va;
693
694   va_start (va, m);
695   error = va_serialize (m, &va);
696   va_end (va);
697   return error;
698 }
699
700 static void *
701 serialize_write_not_inline (serialize_main_header_t * m,
702                             serialize_stream_t * s,
703                             uword n_bytes_to_write, uword flags)
704 {
705   uword cur_bi, n_left_b, n_left_o;
706
707   ASSERT (s->current_buffer_index <= s->n_buffer_bytes);
708   cur_bi = s->current_buffer_index;
709   n_left_b = s->n_buffer_bytes - cur_bi;
710   n_left_o = vec_len (s->overflow_buffer);
711
712   /* Prepend overflow buffer if present. */
713   do
714     {
715       if (n_left_o > 0 && n_left_b > 0)
716         {
717           uword n = clib_min (n_left_b, n_left_o);
718           clib_memcpy_fast (s->buffer + cur_bi, s->overflow_buffer, n);
719           cur_bi += n;
720           n_left_b -= n;
721           n_left_o -= n;
722           if (n_left_o == 0)
723             vec_set_len (s->overflow_buffer, 0);
724           else
725             vec_delete (s->overflow_buffer, n, 0);
726         }
727
728       /* Call data function when buffer is complete.  Data function should
729          dispatch with current buffer and give us a new one to write more
730          data into. */
731       if (n_left_b == 0)
732         {
733           s->current_buffer_index = cur_bi;
734           m->data_function (m, s);
735           cur_bi = s->current_buffer_index;
736           n_left_b = s->n_buffer_bytes - cur_bi;
737         }
738     }
739   while (n_left_o > 0);
740
741   if (n_left_o > 0 || n_left_b < n_bytes_to_write)
742     {
743       u8 *r;
744       s->current_buffer_index = cur_bi;
745       vec_add2 (s->overflow_buffer, r, n_bytes_to_write);
746       return r;
747     }
748   else
749     {
750       s->current_buffer_index = cur_bi + n_bytes_to_write;
751       return s->buffer + cur_bi;
752     }
753 }
754
755 static void *
756 serialize_read_not_inline (serialize_main_header_t * m,
757                            serialize_stream_t * s,
758                            uword n_bytes_to_read, uword flags)
759 {
760   uword cur_bi, cur_oi, n_left_b, n_left_o, n_left_to_read;
761
762   ASSERT (s->current_buffer_index <= s->n_buffer_bytes);
763
764   cur_bi = s->current_buffer_index;
765   cur_oi = s->current_overflow_index;
766
767   n_left_b = s->n_buffer_bytes - cur_bi;
768   n_left_o = vec_len (s->overflow_buffer) - cur_oi;
769
770   /* Read from overflow? */
771   if (n_left_o >= n_bytes_to_read)
772     {
773       s->current_overflow_index = cur_oi + n_bytes_to_read;
774       return vec_elt_at_index (s->overflow_buffer, cur_oi);
775     }
776
777   /* Reset overflow buffer. */
778   if (n_left_o == 0 && s->overflow_buffer)
779     {
780       s->current_overflow_index = 0;
781       vec_set_len (s->overflow_buffer, 0);
782     }
783
784   n_left_to_read = n_bytes_to_read;
785   while (n_left_to_read > 0)
786     {
787       uword n;
788
789       /* If we don't have enough data between overflow and normal buffer
790          call read function. */
791       if (n_left_o + n_left_b < n_bytes_to_read)
792         {
793           /* Save any left over buffer in overflow vector. */
794           if (n_left_b > 0)
795             {
796               vec_add (s->overflow_buffer, s->buffer + cur_bi, n_left_b);
797               n_left_o += n_left_b;
798               n_left_to_read -= n_left_b;
799               /* Advance buffer to end --- even if
800                  SERIALIZE_FLAG_NO_ADVANCE_CURRENT_BUFFER_INDEX is set. */
801               cur_bi = s->n_buffer_bytes;
802               n_left_b = 0;
803             }
804
805           if (m->data_function)
806             {
807               m->data_function (m, s);
808               cur_bi = s->current_buffer_index;
809               n_left_b = s->n_buffer_bytes - cur_bi;
810             }
811         }
812
813       /* For first time through loop return if we have enough data
814          in normal buffer and overflow vector is empty. */
815       if (n_left_o == 0
816           && n_left_to_read == n_bytes_to_read && n_left_b >= n_left_to_read)
817         {
818           s->current_buffer_index = cur_bi + n_bytes_to_read;
819           return s->buffer + cur_bi;
820         }
821
822       if (!m->data_function || serialize_stream_is_end_of_stream (s))
823         {
824           /* This can happen for a peek at end of file.
825              Pad overflow buffer with 0s. */
826           vec_resize (s->overflow_buffer, n_left_to_read);
827           n_left_o += n_left_to_read;
828           n_left_to_read = 0;
829         }
830       else
831         {
832           /* Copy from buffer to overflow vector. */
833           n = clib_min (n_left_to_read, n_left_b);
834           vec_add (s->overflow_buffer, s->buffer + cur_bi, n);
835           cur_bi += n;
836           n_left_b -= n;
837           n_left_o += n;
838           n_left_to_read -= n;
839         }
840     }
841
842   s->current_buffer_index = cur_bi;
843   s->current_overflow_index = cur_oi + n_bytes_to_read;
844   return vec_elt_at_index (s->overflow_buffer, cur_oi);
845 }
846
847 __clib_export void *
848 serialize_read_write_not_inline (serialize_main_header_t * m,
849                                  serialize_stream_t * s,
850                                  uword n_bytes, uword flags)
851 {
852   return (((flags & SERIALIZE_FLAG_IS_READ) ? serialize_read_not_inline :
853            serialize_write_not_inline) (m, s, n_bytes, flags));
854 }
855
856 static void
857 serialize_read_write_close (serialize_main_header_t * m,
858                             serialize_stream_t * s, uword flags)
859 {
860   if (serialize_stream_is_end_of_stream (s))
861     return;
862
863   if (flags & SERIALIZE_FLAG_IS_WRITE)
864     /* "Write" 0 bytes to flush overflow vector. */
865     serialize_write_not_inline (m, s, /* n bytes */ 0, flags);
866
867   serialize_stream_set_end_of_stream (s);
868
869   /* Call it one last time to flush buffer and close. */
870   m->data_function (m, s);
871
872   vec_free (s->overflow_buffer);
873 }
874
875 __clib_export void
876 serialize_close (serialize_main_t * m)
877 {
878   serialize_read_write_close (&m->header, &m->stream,
879                               SERIALIZE_FLAG_IS_WRITE);
880 }
881
882 __clib_export void
883 unserialize_close (serialize_main_t * m)
884 {
885   serialize_read_write_close (&m->header, &m->stream, SERIALIZE_FLAG_IS_READ);
886 }
887
888 __clib_export void
889 serialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes)
890 {
891   clib_memset (m, 0, sizeof (m[0]));
892   m->stream.buffer = data;
893   m->stream.n_buffer_bytes = n_data_bytes;
894 }
895
896 __clib_export void
897 unserialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes)
898 {
899   serialize_open_data (m, data, n_data_bytes);
900 }
901
902 static void
903 serialize_vector_write (serialize_main_header_t * m, serialize_stream_t * s)
904 {
905   if (!serialize_stream_is_end_of_stream (s))
906     {
907       /* Double buffer size. */
908       uword l = vec_len (s->buffer);
909       vec_resize (s->buffer, l > 0 ? l : 64);
910       s->n_buffer_bytes = vec_len (s->buffer);
911     }
912 }
913
914 __clib_export void
915 serialize_open_vector (serialize_main_t * m, u8 * vector)
916 {
917   clib_memset (m, 0, sizeof (m[0]));
918   m->header.data_function = serialize_vector_write;
919   m->stream.buffer = vector;
920   m->stream.current_buffer_index = 0;
921   m->stream.n_buffer_bytes = vec_len (vector);
922 }
923
924 __clib_export void *
925 serialize_close_vector (serialize_main_t * m)
926 {
927   serialize_stream_t *s = &m->stream;
928   void *result;
929
930   serialize_close (m);          /* frees overflow buffer */
931
932   if (s->buffer)
933     vec_set_len (s->buffer, s->current_buffer_index);
934   result = s->buffer;
935   clib_memset (m, 0, sizeof (m[0]));
936   return result;
937 }
938
939 __clib_export void
940 serialize_multiple_1 (serialize_main_t *m, void *data, uword data_stride,
941                       uword n_data)
942 {
943   u8 *d = data;
944   u8 *p;
945   uword n_left = n_data;
946
947   while (n_left >= 4)
948     {
949       p = serialize_get (m, 4 * sizeof (d[0]));
950       p[0] = d[0 * data_stride];
951       p[1] = d[1 * data_stride];
952       p[2] = d[2 * data_stride];
953       p[3] = d[3 * data_stride];
954       n_left -= 4;
955       d += 4 * data_stride;
956     }
957
958   if (n_left > 0)
959     {
960       p = serialize_get (m, n_left * sizeof (p[0]));
961       while (n_left > 0)
962         {
963           p[0] = d[0];
964           p += 1;
965           d += 1 * data_stride;
966           n_left -= 1;
967         }
968     }
969 }
970
971 __clib_export void
972 serialize_multiple_2 (serialize_main_t *m, void *data, uword data_stride,
973                       uword n_data)
974 {
975   void *d = data;
976   u16 *p;
977   uword n_left = n_data;
978
979   while (n_left >= 4)
980     {
981       p = serialize_get (m, 4 * sizeof (p[0]));
982       clib_mem_unaligned (p + 0, u16) =
983         clib_host_to_net_mem_u16 (d + 0 * data_stride);
984       clib_mem_unaligned (p + 1, u16) =
985         clib_host_to_net_mem_u16 (d + 1 * data_stride);
986       clib_mem_unaligned (p + 2, u16) =
987         clib_host_to_net_mem_u16 (d + 2 * data_stride);
988       clib_mem_unaligned (p + 3, u16) =
989         clib_host_to_net_mem_u16 (d + 3 * data_stride);
990       n_left -= 4;
991       d += 4 * data_stride;
992     }
993
994   if (n_left > 0)
995     {
996       p = serialize_get (m, n_left * sizeof (p[0]));
997       while (n_left > 0)
998         {
999           clib_mem_unaligned (p + 0, u16) =
1000             clib_host_to_net_mem_u16 (d + 0 * data_stride);
1001           p += 1;
1002           d += 1 * data_stride;
1003           n_left -= 1;
1004         }
1005     }
1006 }
1007
1008 __clib_export void
1009 serialize_multiple_4 (serialize_main_t *m, void *data, uword data_stride,
1010                       uword n_data)
1011 {
1012   void *d = data;
1013   u32 *p;
1014   uword n_left = n_data;
1015
1016   while (n_left >= 4)
1017     {
1018       p = serialize_get (m, 4 * sizeof (p[0]));
1019       clib_mem_unaligned (p + 0, u32) =
1020         clib_host_to_net_mem_u32 (d + 0 * data_stride);
1021       clib_mem_unaligned (p + 1, u32) =
1022         clib_host_to_net_mem_u32 (d + 1 * data_stride);
1023       clib_mem_unaligned (p + 2, u32) =
1024         clib_host_to_net_mem_u32 (d + 2 * data_stride);
1025       clib_mem_unaligned (p + 3, u32) =
1026         clib_host_to_net_mem_u32 (d + 3 * data_stride);
1027       n_left -= 4;
1028       d += 4 * data_stride;
1029     }
1030
1031   if (n_left > 0)
1032     {
1033       p = serialize_get (m, n_left * sizeof (p[0]));
1034       while (n_left > 0)
1035         {
1036           clib_mem_unaligned (p + 0, u32) =
1037             clib_host_to_net_mem_u32 (d + 0 * data_stride);
1038           p += 1;
1039           d += 1 * data_stride;
1040           n_left -= 1;
1041         }
1042     }
1043 }
1044
1045 __clib_export void
1046 unserialize_multiple_1 (serialize_main_t *m, void *data, uword data_stride,
1047                         uword n_data)
1048 {
1049   u8 *d = data;
1050   u8 *p;
1051   uword n_left = n_data;
1052
1053   while (n_left >= 4)
1054     {
1055       p = unserialize_get (m, 4 * sizeof (d[0]));
1056       d[0 * data_stride] = p[0];
1057       d[1 * data_stride] = p[1];
1058       d[2 * data_stride] = p[2];
1059       d[3 * data_stride] = p[3];
1060       n_left -= 4;
1061       d += 4 * data_stride;
1062     }
1063
1064   if (n_left > 0)
1065     {
1066       p = unserialize_get (m, n_left * sizeof (p[0]));
1067       while (n_left > 0)
1068         {
1069           d[0] = p[0];
1070           p += 1;
1071           d += 1 * data_stride;
1072           n_left -= 1;
1073         }
1074     }
1075 }
1076
1077 __clib_export void
1078 unserialize_multiple_2 (serialize_main_t *m, void *data, uword data_stride,
1079                         uword n_data)
1080 {
1081   void *d = data;
1082   u16 *p;
1083   uword n_left = n_data;
1084
1085   while (n_left >= 4)
1086     {
1087       p = unserialize_get (m, 4 * sizeof (p[0]));
1088       clib_mem_unaligned (d + 0 * data_stride, u16) =
1089         clib_net_to_host_mem_u16 (p + 0);
1090       clib_mem_unaligned (d + 1 * data_stride, u16) =
1091         clib_net_to_host_mem_u16 (p + 1);
1092       clib_mem_unaligned (d + 2 * data_stride, u16) =
1093         clib_net_to_host_mem_u16 (p + 2);
1094       clib_mem_unaligned (d + 3 * data_stride, u16) =
1095         clib_net_to_host_mem_u16 (p + 3);
1096       n_left -= 4;
1097       d += 4 * data_stride;
1098     }
1099
1100   if (n_left > 0)
1101     {
1102       p = unserialize_get (m, n_left * sizeof (p[0]));
1103       while (n_left > 0)
1104         {
1105           clib_mem_unaligned (d + 0 * data_stride, u16) =
1106             clib_net_to_host_mem_u16 (p + 0);
1107           p += 1;
1108           d += 1 * data_stride;
1109           n_left -= 1;
1110         }
1111     }
1112 }
1113
1114 __clib_export void
1115 unserialize_multiple_4 (serialize_main_t *m, void *data, uword data_stride,
1116                         uword n_data)
1117 {
1118   void *d = data;
1119   u32 *p;
1120   uword n_left = n_data;
1121
1122   while (n_left >= 4)
1123     {
1124       p = unserialize_get (m, 4 * sizeof (p[0]));
1125       clib_mem_unaligned (d + 0 * data_stride, u32) =
1126         clib_net_to_host_mem_u32 (p + 0);
1127       clib_mem_unaligned (d + 1 * data_stride, u32) =
1128         clib_net_to_host_mem_u32 (p + 1);
1129       clib_mem_unaligned (d + 2 * data_stride, u32) =
1130         clib_net_to_host_mem_u32 (p + 2);
1131       clib_mem_unaligned (d + 3 * data_stride, u32) =
1132         clib_net_to_host_mem_u32 (p + 3);
1133       n_left -= 4;
1134       d += 4 * data_stride;
1135     }
1136
1137   if (n_left > 0)
1138     {
1139       p = unserialize_get (m, n_left * sizeof (p[0]));
1140       while (n_left > 0)
1141         {
1142           clib_mem_unaligned (d + 0 * data_stride, u32) =
1143             clib_net_to_host_mem_u32 (p + 0);
1144           p += 1;
1145           d += 1 * data_stride;
1146           n_left -= 1;
1147         }
1148     }
1149 }
1150
1151 #ifdef CLIB_UNIX
1152
1153 #include <unistd.h>
1154 #include <fcntl.h>
1155
1156 static void
1157 clib_file_write (serialize_main_header_t * m, serialize_stream_t * s)
1158 {
1159   int fd, n;
1160
1161   fd = s->data_function_opaque;
1162   n = write (fd, s->buffer, s->current_buffer_index);
1163   if (n < 0)
1164     {
1165       if (!unix_error_is_fatal (errno))
1166         n = 0;
1167       else
1168         serialize_error (m, clib_error_return_unix (0, "write"));
1169     }
1170   if (n == s->current_buffer_index)
1171     vec_set_len (s->buffer, 0);
1172   else
1173     vec_delete (s->buffer, n, 0);
1174   s->current_buffer_index = vec_len (s->buffer);
1175 }
1176
1177 static void
1178 clib_file_read (serialize_main_header_t * m, serialize_stream_t * s)
1179 {
1180   int fd, n;
1181
1182   fd = s->data_function_opaque;
1183   n = read (fd, s->buffer, vec_len (s->buffer));
1184   if (n < 0)
1185     {
1186       if (!unix_error_is_fatal (errno))
1187         n = 0;
1188       else
1189         serialize_error (m, clib_error_return_unix (0, "read"));
1190     }
1191   else if (n == 0)
1192     serialize_stream_set_end_of_stream (s);
1193   s->current_buffer_index = 0;
1194   s->n_buffer_bytes = n;
1195 }
1196
1197 static void
1198 serialize_open_clib_file_descriptor_helper (serialize_main_t * m, int fd,
1199                                             uword is_read)
1200 {
1201   clib_memset (m, 0, sizeof (m[0]));
1202   vec_resize (m->stream.buffer, 4096);
1203
1204   if (!is_read)
1205     {
1206       m->stream.n_buffer_bytes = vec_len (m->stream.buffer);
1207       vec_set_len (m->stream.buffer, 0);
1208     }
1209
1210   m->header.data_function = is_read ? clib_file_read : clib_file_write;
1211   m->stream.data_function_opaque = fd;
1212 }
1213
1214 __clib_export void
1215 serialize_open_clib_file_descriptor (serialize_main_t * m, int fd)
1216 {
1217   serialize_open_clib_file_descriptor_helper (m, fd, /* is_read */ 0);
1218 }
1219
1220 __clib_export void
1221 unserialize_open_clib_file_descriptor (serialize_main_t * m, int fd)
1222 {
1223   serialize_open_clib_file_descriptor_helper (m, fd, /* is_read */ 1);
1224 }
1225
1226 static clib_error_t *
1227 serialize_open_clib_file_helper (serialize_main_t * m, char *file,
1228                                  uword is_read)
1229 {
1230   int fd, mode;
1231
1232   mode = is_read ? O_RDONLY : O_RDWR | O_CREAT | O_TRUNC;
1233   fd = open (file, mode, 0666);
1234   if (fd < 0)
1235     return clib_error_return_unix (0, "open `%s'", file);
1236
1237   serialize_open_clib_file_descriptor_helper (m, fd, is_read);
1238   return 0;
1239 }
1240
1241 __clib_export clib_error_t *
1242 serialize_open_clib_file (serialize_main_t * m, char *file)
1243 {
1244   return serialize_open_clib_file_helper (m, file, /* is_read */ 0);
1245 }
1246
1247 __clib_export clib_error_t *
1248 unserialize_open_clib_file (serialize_main_t * m, char *file)
1249 {
1250   return serialize_open_clib_file_helper (m, file, /* is_read */ 1);
1251 }
1252
1253 #endif /* CLIB_UNIX */
1254
1255 /*
1256  * fd.io coding-style-patch-verification: ON
1257  *
1258  * Local Variables:
1259  * eval: (c-set-style "gnu")
1260  * End:
1261  */