ipsec: make chacha20-poly1305 available via API
[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       vec_add2 (s->overflow_buffer, r, n_bytes_to_write);
745       return r;
746     }
747   else
748     {
749       s->current_buffer_index = cur_bi + n_bytes_to_write;
750       return s->buffer + cur_bi;
751     }
752 }
753
754 static void *
755 serialize_read_not_inline (serialize_main_header_t * m,
756                            serialize_stream_t * s,
757                            uword n_bytes_to_read, uword flags)
758 {
759   uword cur_bi, cur_oi, n_left_b, n_left_o, n_left_to_read;
760
761   ASSERT (s->current_buffer_index <= s->n_buffer_bytes);
762
763   cur_bi = s->current_buffer_index;
764   cur_oi = s->current_overflow_index;
765
766   n_left_b = s->n_buffer_bytes - cur_bi;
767   n_left_o = vec_len (s->overflow_buffer) - cur_oi;
768
769   /* Read from overflow? */
770   if (n_left_o >= n_bytes_to_read)
771     {
772       s->current_overflow_index = cur_oi + n_bytes_to_read;
773       return vec_elt_at_index (s->overflow_buffer, cur_oi);
774     }
775
776   /* Reset overflow buffer. */
777   if (n_left_o == 0 && s->overflow_buffer)
778     {
779       s->current_overflow_index = 0;
780       vec_set_len (s->overflow_buffer, 0);
781     }
782
783   n_left_to_read = n_bytes_to_read;
784   while (n_left_to_read > 0)
785     {
786       uword n;
787
788       /* If we don't have enough data between overflow and normal buffer
789          call read function. */
790       if (n_left_o + n_left_b < n_bytes_to_read)
791         {
792           /* Save any left over buffer in overflow vector. */
793           if (n_left_b > 0)
794             {
795               vec_add (s->overflow_buffer, s->buffer + cur_bi, n_left_b);
796               n_left_o += n_left_b;
797               n_left_to_read -= n_left_b;
798               /* Advance buffer to end --- even if
799                  SERIALIZE_FLAG_NO_ADVANCE_CURRENT_BUFFER_INDEX is set. */
800               cur_bi = s->n_buffer_bytes;
801               n_left_b = 0;
802             }
803
804           if (m->data_function)
805             {
806               m->data_function (m, s);
807               cur_bi = s->current_buffer_index;
808               n_left_b = s->n_buffer_bytes - cur_bi;
809             }
810         }
811
812       /* For first time through loop return if we have enough data
813          in normal buffer and overflow vector is empty. */
814       if (n_left_o == 0
815           && n_left_to_read == n_bytes_to_read && n_left_b >= n_left_to_read)
816         {
817           s->current_buffer_index = cur_bi + n_bytes_to_read;
818           return s->buffer + cur_bi;
819         }
820
821       if (!m->data_function || serialize_stream_is_end_of_stream (s))
822         {
823           /* This can happen for a peek at end of file.
824              Pad overflow buffer with 0s. */
825           vec_resize (s->overflow_buffer, n_left_to_read);
826           n_left_o += n_left_to_read;
827           n_left_to_read = 0;
828         }
829       else
830         {
831           /* Copy from buffer to overflow vector. */
832           n = clib_min (n_left_to_read, n_left_b);
833           vec_add (s->overflow_buffer, s->buffer + cur_bi, n);
834           cur_bi += n;
835           n_left_b -= n;
836           n_left_o += n;
837           n_left_to_read -= n;
838         }
839     }
840
841   s->current_buffer_index = cur_bi;
842   s->current_overflow_index = cur_oi + n_bytes_to_read;
843   return vec_elt_at_index (s->overflow_buffer, cur_oi);
844 }
845
846 __clib_export void *
847 serialize_read_write_not_inline (serialize_main_header_t * m,
848                                  serialize_stream_t * s,
849                                  uword n_bytes, uword flags)
850 {
851   return (((flags & SERIALIZE_FLAG_IS_READ) ? serialize_read_not_inline :
852            serialize_write_not_inline) (m, s, n_bytes, flags));
853 }
854
855 static void
856 serialize_read_write_close (serialize_main_header_t * m,
857                             serialize_stream_t * s, uword flags)
858 {
859   if (serialize_stream_is_end_of_stream (s))
860     return;
861
862   if (flags & SERIALIZE_FLAG_IS_WRITE)
863     /* "Write" 0 bytes to flush overflow vector. */
864     serialize_write_not_inline (m, s, /* n bytes */ 0, flags);
865
866   serialize_stream_set_end_of_stream (s);
867
868   /* Call it one last time to flush buffer and close. */
869   m->data_function (m, s);
870
871   vec_free (s->overflow_buffer);
872 }
873
874 __clib_export void
875 serialize_close (serialize_main_t * m)
876 {
877   serialize_read_write_close (&m->header, &m->stream,
878                               SERIALIZE_FLAG_IS_WRITE);
879 }
880
881 __clib_export void
882 unserialize_close (serialize_main_t * m)
883 {
884   serialize_read_write_close (&m->header, &m->stream, SERIALIZE_FLAG_IS_READ);
885 }
886
887 __clib_export void
888 serialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes)
889 {
890   clib_memset (m, 0, sizeof (m[0]));
891   m->stream.buffer = data;
892   m->stream.n_buffer_bytes = n_data_bytes;
893 }
894
895 __clib_export void
896 unserialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes)
897 {
898   serialize_open_data (m, data, n_data_bytes);
899 }
900
901 static void
902 serialize_vector_write (serialize_main_header_t * m, serialize_stream_t * s)
903 {
904   if (!serialize_stream_is_end_of_stream (s))
905     {
906       /* Double buffer size. */
907       uword l = vec_len (s->buffer);
908       vec_resize (s->buffer, l > 0 ? l : 64);
909       s->n_buffer_bytes = vec_len (s->buffer);
910     }
911 }
912
913 __clib_export void
914 serialize_open_vector (serialize_main_t * m, u8 * vector)
915 {
916   clib_memset (m, 0, sizeof (m[0]));
917   m->header.data_function = serialize_vector_write;
918   m->stream.buffer = vector;
919   m->stream.current_buffer_index = 0;
920   m->stream.n_buffer_bytes = vec_len (vector);
921 }
922
923 __clib_export void *
924 serialize_close_vector (serialize_main_t * m)
925 {
926   serialize_stream_t *s = &m->stream;
927   void *result;
928
929   serialize_close (m);          /* frees overflow buffer */
930
931   if (s->buffer)
932     vec_set_len (s->buffer, s->current_buffer_index);
933   result = s->buffer;
934   clib_memset (m, 0, sizeof (m[0]));
935   return result;
936 }
937
938 __clib_export void
939 serialize_multiple_1 (serialize_main_t *m, void *data, uword data_stride,
940                       uword n_data)
941 {
942   u8 *d = data;
943   u8 *p;
944   uword n_left = n_data;
945
946   while (n_left >= 4)
947     {
948       p = serialize_get (m, 4 * sizeof (d[0]));
949       p[0] = d[0 * data_stride];
950       p[1] = d[1 * data_stride];
951       p[2] = d[2 * data_stride];
952       p[3] = d[3 * data_stride];
953       n_left -= 4;
954       d += 4 * data_stride;
955     }
956
957   if (n_left > 0)
958     {
959       p = serialize_get (m, n_left * sizeof (p[0]));
960       while (n_left > 0)
961         {
962           p[0] = d[0];
963           p += 1;
964           d += 1 * data_stride;
965           n_left -= 1;
966         }
967     }
968 }
969
970 __clib_export void
971 serialize_multiple_2 (serialize_main_t *m, void *data, uword data_stride,
972                       uword n_data)
973 {
974   void *d = data;
975   u16 *p;
976   uword n_left = n_data;
977
978   while (n_left >= 4)
979     {
980       p = serialize_get (m, 4 * sizeof (p[0]));
981       clib_mem_unaligned (p + 0, u16) =
982         clib_host_to_net_mem_u16 (d + 0 * data_stride);
983       clib_mem_unaligned (p + 1, u16) =
984         clib_host_to_net_mem_u16 (d + 1 * data_stride);
985       clib_mem_unaligned (p + 2, u16) =
986         clib_host_to_net_mem_u16 (d + 2 * data_stride);
987       clib_mem_unaligned (p + 3, u16) =
988         clib_host_to_net_mem_u16 (d + 3 * data_stride);
989       n_left -= 4;
990       d += 4 * data_stride;
991     }
992
993   if (n_left > 0)
994     {
995       p = serialize_get (m, n_left * sizeof (p[0]));
996       while (n_left > 0)
997         {
998           clib_mem_unaligned (p + 0, u16) =
999             clib_host_to_net_mem_u16 (d + 0 * data_stride);
1000           p += 1;
1001           d += 1 * data_stride;
1002           n_left -= 1;
1003         }
1004     }
1005 }
1006
1007 __clib_export void
1008 serialize_multiple_4 (serialize_main_t *m, void *data, uword data_stride,
1009                       uword n_data)
1010 {
1011   void *d = data;
1012   u32 *p;
1013   uword n_left = n_data;
1014
1015   while (n_left >= 4)
1016     {
1017       p = serialize_get (m, 4 * sizeof (p[0]));
1018       clib_mem_unaligned (p + 0, u32) =
1019         clib_host_to_net_mem_u32 (d + 0 * data_stride);
1020       clib_mem_unaligned (p + 1, u32) =
1021         clib_host_to_net_mem_u32 (d + 1 * data_stride);
1022       clib_mem_unaligned (p + 2, u32) =
1023         clib_host_to_net_mem_u32 (d + 2 * data_stride);
1024       clib_mem_unaligned (p + 3, u32) =
1025         clib_host_to_net_mem_u32 (d + 3 * data_stride);
1026       n_left -= 4;
1027       d += 4 * data_stride;
1028     }
1029
1030   if (n_left > 0)
1031     {
1032       p = serialize_get (m, n_left * sizeof (p[0]));
1033       while (n_left > 0)
1034         {
1035           clib_mem_unaligned (p + 0, u32) =
1036             clib_host_to_net_mem_u32 (d + 0 * data_stride);
1037           p += 1;
1038           d += 1 * data_stride;
1039           n_left -= 1;
1040         }
1041     }
1042 }
1043
1044 __clib_export void
1045 unserialize_multiple_1 (serialize_main_t *m, void *data, uword data_stride,
1046                         uword n_data)
1047 {
1048   u8 *d = data;
1049   u8 *p;
1050   uword n_left = n_data;
1051
1052   while (n_left >= 4)
1053     {
1054       p = unserialize_get (m, 4 * sizeof (d[0]));
1055       d[0 * data_stride] = p[0];
1056       d[1 * data_stride] = p[1];
1057       d[2 * data_stride] = p[2];
1058       d[3 * data_stride] = p[3];
1059       n_left -= 4;
1060       d += 4 * data_stride;
1061     }
1062
1063   if (n_left > 0)
1064     {
1065       p = unserialize_get (m, n_left * sizeof (p[0]));
1066       while (n_left > 0)
1067         {
1068           d[0] = p[0];
1069           p += 1;
1070           d += 1 * data_stride;
1071           n_left -= 1;
1072         }
1073     }
1074 }
1075
1076 __clib_export void
1077 unserialize_multiple_2 (serialize_main_t *m, void *data, uword data_stride,
1078                         uword n_data)
1079 {
1080   void *d = data;
1081   u16 *p;
1082   uword n_left = n_data;
1083
1084   while (n_left >= 4)
1085     {
1086       p = unserialize_get (m, 4 * sizeof (p[0]));
1087       clib_mem_unaligned (d + 0 * data_stride, u16) =
1088         clib_net_to_host_mem_u16 (p + 0);
1089       clib_mem_unaligned (d + 1 * data_stride, u16) =
1090         clib_net_to_host_mem_u16 (p + 1);
1091       clib_mem_unaligned (d + 2 * data_stride, u16) =
1092         clib_net_to_host_mem_u16 (p + 2);
1093       clib_mem_unaligned (d + 3 * data_stride, u16) =
1094         clib_net_to_host_mem_u16 (p + 3);
1095       n_left -= 4;
1096       d += 4 * data_stride;
1097     }
1098
1099   if (n_left > 0)
1100     {
1101       p = unserialize_get (m, n_left * sizeof (p[0]));
1102       while (n_left > 0)
1103         {
1104           clib_mem_unaligned (d + 0 * data_stride, u16) =
1105             clib_net_to_host_mem_u16 (p + 0);
1106           p += 1;
1107           d += 1 * data_stride;
1108           n_left -= 1;
1109         }
1110     }
1111 }
1112
1113 __clib_export void
1114 unserialize_multiple_4 (serialize_main_t *m, void *data, uword data_stride,
1115                         uword n_data)
1116 {
1117   void *d = data;
1118   u32 *p;
1119   uword n_left = n_data;
1120
1121   while (n_left >= 4)
1122     {
1123       p = unserialize_get (m, 4 * sizeof (p[0]));
1124       clib_mem_unaligned (d + 0 * data_stride, u32) =
1125         clib_net_to_host_mem_u32 (p + 0);
1126       clib_mem_unaligned (d + 1 * data_stride, u32) =
1127         clib_net_to_host_mem_u32 (p + 1);
1128       clib_mem_unaligned (d + 2 * data_stride, u32) =
1129         clib_net_to_host_mem_u32 (p + 2);
1130       clib_mem_unaligned (d + 3 * data_stride, u32) =
1131         clib_net_to_host_mem_u32 (p + 3);
1132       n_left -= 4;
1133       d += 4 * data_stride;
1134     }
1135
1136   if (n_left > 0)
1137     {
1138       p = unserialize_get (m, n_left * sizeof (p[0]));
1139       while (n_left > 0)
1140         {
1141           clib_mem_unaligned (d + 0 * data_stride, u32) =
1142             clib_net_to_host_mem_u32 (p + 0);
1143           p += 1;
1144           d += 1 * data_stride;
1145           n_left -= 1;
1146         }
1147     }
1148 }
1149
1150 #ifdef CLIB_UNIX
1151
1152 #include <unistd.h>
1153 #include <fcntl.h>
1154
1155 static void
1156 clib_file_write (serialize_main_header_t * m, serialize_stream_t * s)
1157 {
1158   int fd, n;
1159
1160   fd = s->data_function_opaque;
1161   n = write (fd, s->buffer, s->current_buffer_index);
1162   if (n < 0)
1163     {
1164       if (!unix_error_is_fatal (errno))
1165         n = 0;
1166       else
1167         serialize_error (m, clib_error_return_unix (0, "write"));
1168     }
1169   if (n == s->current_buffer_index)
1170     vec_set_len (s->buffer, 0);
1171   else
1172     vec_delete (s->buffer, n, 0);
1173   s->current_buffer_index = vec_len (s->buffer);
1174 }
1175
1176 static void
1177 clib_file_read (serialize_main_header_t * m, serialize_stream_t * s)
1178 {
1179   int fd, n;
1180
1181   fd = s->data_function_opaque;
1182   n = read (fd, s->buffer, vec_len (s->buffer));
1183   if (n < 0)
1184     {
1185       if (!unix_error_is_fatal (errno))
1186         n = 0;
1187       else
1188         serialize_error (m, clib_error_return_unix (0, "read"));
1189     }
1190   else if (n == 0)
1191     serialize_stream_set_end_of_stream (s);
1192   s->current_buffer_index = 0;
1193   s->n_buffer_bytes = n;
1194 }
1195
1196 static void
1197 serialize_open_clib_file_descriptor_helper (serialize_main_t * m, int fd,
1198                                             uword is_read)
1199 {
1200   clib_memset (m, 0, sizeof (m[0]));
1201   vec_resize (m->stream.buffer, 4096);
1202
1203   if (!is_read)
1204     {
1205       m->stream.n_buffer_bytes = vec_len (m->stream.buffer);
1206       vec_set_len (m->stream.buffer, 0);
1207     }
1208
1209   m->header.data_function = is_read ? clib_file_read : clib_file_write;
1210   m->stream.data_function_opaque = fd;
1211 }
1212
1213 __clib_export void
1214 serialize_open_clib_file_descriptor (serialize_main_t * m, int fd)
1215 {
1216   serialize_open_clib_file_descriptor_helper (m, fd, /* is_read */ 0);
1217 }
1218
1219 __clib_export void
1220 unserialize_open_clib_file_descriptor (serialize_main_t * m, int fd)
1221 {
1222   serialize_open_clib_file_descriptor_helper (m, fd, /* is_read */ 1);
1223 }
1224
1225 static clib_error_t *
1226 serialize_open_clib_file_helper (serialize_main_t * m, char *file,
1227                                  uword is_read)
1228 {
1229   int fd, mode;
1230
1231   mode = is_read ? O_RDONLY : O_RDWR | O_CREAT | O_TRUNC;
1232   fd = open (file, mode, 0666);
1233   if (fd < 0)
1234     return clib_error_return_unix (0, "open `%s'", file);
1235
1236   serialize_open_clib_file_descriptor_helper (m, fd, is_read);
1237   return 0;
1238 }
1239
1240 __clib_export clib_error_t *
1241 serialize_open_clib_file (serialize_main_t * m, char *file)
1242 {
1243   return serialize_open_clib_file_helper (m, file, /* is_read */ 0);
1244 }
1245
1246 __clib_export clib_error_t *
1247 unserialize_open_clib_file (serialize_main_t * m, char *file)
1248 {
1249   return serialize_open_clib_file_helper (m, file, /* is_read */ 1);
1250 }
1251
1252 #endif /* CLIB_UNIX */
1253
1254 /*
1255  * fd.io coding-style-patch-verification: ON
1256  *
1257  * Local Variables:
1258  * eval: (c-set-style "gnu")
1259  * End:
1260  */