Type: fix Change-Id: If59a66aae658dd35dbcb4987ab00c306b3c6e2e2 Signed-off-by: Damjan Marion <damarion@cisco.com>
1256 lines
30 KiB
C
1256 lines
30 KiB
C
/*
|
|
* Copyright (c) 2015 Cisco and/or its affiliates.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/*
|
|
Copyright (c) 2005 Eliot Dresselhaus
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
a copy of this software and associated documentation files (the
|
|
"Software"), to deal in the Software without restriction, including
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
/* Turn data structures into byte streams for saving or transport. */
|
|
|
|
#include <vppinfra/heap.h>
|
|
#include <vppinfra/pool.h>
|
|
#include <vppinfra/serialize.h>
|
|
|
|
void
|
|
serialize_64 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u64 x = va_arg (*va, u64);
|
|
u32 lo, hi;
|
|
lo = x;
|
|
hi = x >> 32;
|
|
serialize_integer (m, lo, sizeof (lo));
|
|
serialize_integer (m, hi, sizeof (hi));
|
|
}
|
|
|
|
void
|
|
serialize_32 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u32 x = va_arg (*va, u32);
|
|
serialize_integer (m, x, sizeof (x));
|
|
}
|
|
|
|
void
|
|
serialize_16 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u32 x = va_arg (*va, u32);
|
|
serialize_integer (m, x, sizeof (u16));
|
|
}
|
|
|
|
void
|
|
serialize_8 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u32 x = va_arg (*va, u32);
|
|
serialize_integer (m, x, sizeof (u8));
|
|
}
|
|
|
|
void
|
|
unserialize_64 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u64 *x = va_arg (*va, u64 *);
|
|
u32 lo, hi;
|
|
unserialize_integer (m, &lo, sizeof (lo));
|
|
unserialize_integer (m, &hi, sizeof (hi));
|
|
*x = ((u64) hi << 32) | (u64) lo;
|
|
}
|
|
|
|
void
|
|
unserialize_32 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u32 *x = va_arg (*va, u32 *);
|
|
unserialize_integer (m, x, sizeof (x[0]));
|
|
}
|
|
|
|
void
|
|
unserialize_16 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u16 *x = va_arg (*va, u16 *);
|
|
u32 t;
|
|
unserialize_integer (m, &t, sizeof (x[0]));
|
|
x[0] = t;
|
|
}
|
|
|
|
void
|
|
unserialize_8 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u8 *x = va_arg (*va, u8 *);
|
|
u32 t;
|
|
unserialize_integer (m, &t, sizeof (x[0]));
|
|
x[0] = t;
|
|
}
|
|
|
|
void
|
|
serialize_f64 (serialize_main_t * m, va_list * va)
|
|
{
|
|
f64 x = va_arg (*va, f64);
|
|
union
|
|
{
|
|
f64 f;
|
|
u64 i;
|
|
} y;
|
|
y.f = x;
|
|
serialize (m, serialize_64, y.i);
|
|
}
|
|
|
|
void
|
|
serialize_f32 (serialize_main_t * m, va_list * va)
|
|
{
|
|
f32 x = va_arg (*va, f64);
|
|
union
|
|
{
|
|
f32 f;
|
|
u32 i;
|
|
} y;
|
|
y.f = x;
|
|
serialize_integer (m, y.i, sizeof (y.i));
|
|
}
|
|
|
|
void
|
|
unserialize_f64 (serialize_main_t * m, va_list * va)
|
|
{
|
|
f64 *x = va_arg (*va, f64 *);
|
|
union
|
|
{
|
|
f64 f;
|
|
u64 i;
|
|
} y;
|
|
unserialize (m, unserialize_64, &y.i);
|
|
*x = y.f;
|
|
}
|
|
|
|
void
|
|
unserialize_f32 (serialize_main_t * m, va_list * va)
|
|
{
|
|
f32 *x = va_arg (*va, f32 *);
|
|
union
|
|
{
|
|
f32 f;
|
|
u32 i;
|
|
} y;
|
|
unserialize_integer (m, &y.i, sizeof (y.i));
|
|
*x = y.f;
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_cstring (serialize_main_t * m, char *s)
|
|
{
|
|
u32 len = s ? strlen (s) : 0;
|
|
void *p;
|
|
|
|
serialize_likely_small_unsigned_integer (m, len);
|
|
if (len > 0)
|
|
{
|
|
p = serialize_get (m, len);
|
|
clib_memcpy_fast (p, s, len);
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_cstring (serialize_main_t * m, char **s)
|
|
{
|
|
char *p, *r = 0;
|
|
u32 len;
|
|
|
|
len = unserialize_likely_small_unsigned_integer (m);
|
|
|
|
/*
|
|
* Given broken enough data, we could get len = 0xFFFFFFFF.
|
|
* Add one, it overflows, we call vec_new (char, 0), then
|
|
* memcpy until we bus error.
|
|
*/
|
|
if (len > 0 && len != 0xFFFFFFFF)
|
|
{
|
|
r = vec_new (char, len + 1);
|
|
p = unserialize_get (m, len);
|
|
clib_memcpy_fast (r, p, len);
|
|
|
|
/* Null terminate. */
|
|
r[len] = 0;
|
|
}
|
|
*s = r;
|
|
}
|
|
|
|
/* vec_serialize/vec_unserialize helper functions for basic vector types. */
|
|
void
|
|
serialize_vec_8 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u8 *s = va_arg (*va, u8 *);
|
|
u32 n = va_arg (*va, u32);
|
|
u8 *p = serialize_get (m, n * sizeof (u8));
|
|
clib_memcpy_fast (p, s, n * sizeof (u8));
|
|
}
|
|
|
|
void
|
|
unserialize_vec_8 (serialize_main_t * m, va_list * va)
|
|
{
|
|
u8 *s = va_arg (*va, u8 *);
|
|
u32 n = va_arg (*va, u32);
|
|
u8 *p = unserialize_get (m, n);
|
|
clib_memcpy_fast (s, p, n);
|
|
}
|
|
|
|
#define _(n_bits) \
|
|
void serialize_vec_##n_bits (serialize_main_t * m, va_list * va) \
|
|
{ \
|
|
u##n_bits * s = va_arg (*va, u##n_bits *); \
|
|
u32 n = va_arg (*va, u32); \
|
|
u##n_bits * p = serialize_get (m, n * sizeof (s[0])); \
|
|
\
|
|
while (n >= 4) \
|
|
{ \
|
|
p[0] = clib_host_to_net_u##n_bits (s[0]); \
|
|
p[1] = clib_host_to_net_u##n_bits (s[1]); \
|
|
p[2] = clib_host_to_net_u##n_bits (s[2]); \
|
|
p[3] = clib_host_to_net_u##n_bits (s[3]); \
|
|
s += 4; \
|
|
p += 4; \
|
|
n -= 4; \
|
|
} \
|
|
\
|
|
while (n >= 1) \
|
|
{ \
|
|
p[0] = clib_host_to_net_u##n_bits (s[0]); \
|
|
s += 1; \
|
|
p += 1; \
|
|
n -= 1; \
|
|
} \
|
|
} \
|
|
\
|
|
void unserialize_vec_##n_bits (serialize_main_t * m, va_list * va) \
|
|
{ \
|
|
u##n_bits * s = va_arg (*va, u##n_bits *); \
|
|
u32 n = va_arg (*va, u32); \
|
|
u##n_bits * p = unserialize_get (m, n * sizeof (s[0])); \
|
|
\
|
|
while (n >= 4) \
|
|
{ \
|
|
s[0] = clib_net_to_host_mem_u##n_bits (&p[0]); \
|
|
s[1] = clib_net_to_host_mem_u##n_bits (&p[1]); \
|
|
s[2] = clib_net_to_host_mem_u##n_bits (&p[2]); \
|
|
s[3] = clib_net_to_host_mem_u##n_bits (&p[3]); \
|
|
s += 4; \
|
|
p += 4; \
|
|
n -= 4; \
|
|
} \
|
|
\
|
|
while (n >= 1) \
|
|
{ \
|
|
s[0] = clib_net_to_host_mem_u##n_bits (&p[0]); \
|
|
s += 1; \
|
|
p += 1; \
|
|
n -= 1; \
|
|
} \
|
|
}
|
|
|
|
_(16);
|
|
_(32);
|
|
_(64);
|
|
|
|
#undef _
|
|
|
|
#define SERIALIZE_VECTOR_CHUNK_SIZE 64
|
|
|
|
__clib_export void
|
|
serialize_vector (serialize_main_t * m, va_list * va)
|
|
{
|
|
void *vec = va_arg (*va, void *);
|
|
u32 elt_bytes = va_arg (*va, u32);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
u32 l = vec_len (vec);
|
|
void *p = vec;
|
|
|
|
serialize_integer (m, l, sizeof (l));
|
|
|
|
/* Serialize vector in chunks for cache locality. */
|
|
while (l != 0)
|
|
{
|
|
u32 n = clib_min (SERIALIZE_VECTOR_CHUNK_SIZE, l);
|
|
serialize (m, f, p, n);
|
|
l -= n;
|
|
p += SERIALIZE_VECTOR_CHUNK_SIZE * elt_bytes;
|
|
}
|
|
}
|
|
|
|
void *
|
|
unserialize_vector_ha (serialize_main_t * m,
|
|
u32 elt_bytes,
|
|
u32 header_bytes,
|
|
u32 align, u32 max_length, serialize_function_t * f)
|
|
{
|
|
void *v, *p;
|
|
u32 l;
|
|
|
|
unserialize_integer (m, &l, sizeof (l));
|
|
if (l > max_length)
|
|
serialize_error (&m->header,
|
|
clib_error_create ("bad vector length %d", l));
|
|
p = v = _vec_resize ((void *) 0, l, (uword) l * elt_bytes, header_bytes,
|
|
/* align */ align);
|
|
|
|
while (l != 0)
|
|
{
|
|
u32 n = clib_min (SERIALIZE_VECTOR_CHUNK_SIZE, l);
|
|
unserialize (m, f, p, n);
|
|
l -= n;
|
|
p += SERIALIZE_VECTOR_CHUNK_SIZE * elt_bytes;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
void
|
|
unserialize_aligned_vector (serialize_main_t * m, va_list * va)
|
|
{
|
|
void **vec = va_arg (*va, void **);
|
|
u32 elt_bytes = va_arg (*va, u32);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
u32 align = va_arg (*va, u32);
|
|
|
|
*vec = unserialize_vector_ha (m, elt_bytes,
|
|
/* header_bytes */ 0,
|
|
/* align */ align,
|
|
/* max_length */ ~0,
|
|
f);
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_vector (serialize_main_t * m, va_list * va)
|
|
{
|
|
void **vec = va_arg (*va, void **);
|
|
u32 elt_bytes = va_arg (*va, u32);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
|
|
*vec = unserialize_vector_ha (m, elt_bytes,
|
|
/* header_bytes */ 0,
|
|
/* align */ 0,
|
|
/* max_length */ ~0,
|
|
f);
|
|
}
|
|
|
|
void
|
|
serialize_bitmap (serialize_main_t * m, uword * b)
|
|
{
|
|
u32 l, i, n_u32s;
|
|
|
|
l = vec_len (b);
|
|
n_u32s = l * sizeof (b[0]) / sizeof (u32);
|
|
serialize_integer (m, n_u32s, sizeof (n_u32s));
|
|
|
|
/* Send 32 bit words, low-order word first on 64 bit. */
|
|
for (i = 0; i < l; i++)
|
|
{
|
|
serialize_integer (m, b[i], sizeof (u32));
|
|
if (BITS (uword) == 64)
|
|
serialize_integer (m, (u64) b[i] >> (u64) 32, sizeof (u32));
|
|
}
|
|
}
|
|
|
|
uword *
|
|
unserialize_bitmap (serialize_main_t * m)
|
|
{
|
|
uword *b = 0;
|
|
u32 i, n_u32s;
|
|
|
|
unserialize_integer (m, &n_u32s, sizeof (n_u32s));
|
|
if (n_u32s == 0)
|
|
return b;
|
|
|
|
i = (n_u32s * sizeof (u32) + sizeof (b[0]) - 1) / sizeof (b[0]);
|
|
vec_resize (b, i);
|
|
for (i = 0; i < n_u32s; i++)
|
|
{
|
|
u32 data;
|
|
unserialize_integer (m, &data, sizeof (u32));
|
|
|
|
/* Low-word is first on 64 bit. */
|
|
if (BITS (uword) == 64)
|
|
{
|
|
if ((i % 2) == 0)
|
|
b[i / 2] |= (u64) data << (u64) 0;
|
|
else
|
|
b[i / 2] |= (u64) data << (u64) 32;
|
|
}
|
|
else
|
|
{
|
|
b[i] = data;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
void
|
|
serialize_pool (serialize_main_t * m, va_list * va)
|
|
{
|
|
void *pool = va_arg (*va, void *);
|
|
u32 elt_bytes = va_arg (*va, u32);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
u32 l, lo, hi;
|
|
pool_header_t *p;
|
|
|
|
l = vec_len (pool);
|
|
serialize_integer (m, l, sizeof (u32));
|
|
if (l == 0)
|
|
return;
|
|
p = pool_header (pool);
|
|
|
|
/* No need to send free bitmap. Need to send index vector
|
|
to guarantee that unserialized pool will be identical. */
|
|
vec_serialize (m, p->free_indices, serialize_vec_32);
|
|
|
|
pool_foreach_region (lo, hi, pool,
|
|
serialize (m, f, pool + lo * elt_bytes, hi - lo));
|
|
}
|
|
|
|
static void *
|
|
unserialize_pool_helper (serialize_main_t * m,
|
|
u32 elt_bytes, u32 align, serialize_function_t * f)
|
|
{
|
|
void *v;
|
|
u32 i, l, lo, hi;
|
|
pool_header_t *p;
|
|
|
|
unserialize_integer (m, &l, sizeof (l));
|
|
if (l == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
v = _vec_resize ((void *) 0, l, (uword) l * elt_bytes, sizeof (p[0]),
|
|
align);
|
|
p = pool_header (v);
|
|
|
|
vec_unserialize (m, &p->free_indices, unserialize_vec_32);
|
|
|
|
/* Construct free bitmap. */
|
|
p->free_bitmap = 0;
|
|
for (i = 0; i < vec_len (p->free_indices); i++)
|
|
p->free_bitmap = clib_bitmap_ori (p->free_bitmap, p->free_indices[i]);
|
|
|
|
pool_foreach_region (lo, hi, v,
|
|
unserialize (m, f, v + lo * elt_bytes, hi - lo));
|
|
|
|
return v;
|
|
}
|
|
|
|
void
|
|
unserialize_pool (serialize_main_t * m, va_list * va)
|
|
{
|
|
void **result = va_arg (*va, void **);
|
|
u32 elt_bytes = va_arg (*va, u32);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
*result = unserialize_pool_helper (m, elt_bytes, /* align */ 0, f);
|
|
}
|
|
|
|
void
|
|
unserialize_aligned_pool (serialize_main_t * m, va_list * va)
|
|
{
|
|
void **result = va_arg (*va, void **);
|
|
u32 elt_bytes = va_arg (*va, u32);
|
|
u32 align = va_arg (*va, u32);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
*result = unserialize_pool_helper (m, elt_bytes, align, f);
|
|
}
|
|
|
|
static void
|
|
serialize_vec_heap_elt (serialize_main_t * m, va_list * va)
|
|
{
|
|
heap_elt_t *e = va_arg (*va, heap_elt_t *);
|
|
u32 i, n = va_arg (*va, u32);
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
serialize_integer (m, e[i].offset, sizeof (e[i].offset));
|
|
serialize_integer (m, e[i].next, sizeof (e[i].next));
|
|
serialize_integer (m, e[i].prev, sizeof (e[i].prev));
|
|
}
|
|
}
|
|
|
|
static void
|
|
unserialize_vec_heap_elt (serialize_main_t * m, va_list * va)
|
|
{
|
|
heap_elt_t *e = va_arg (*va, heap_elt_t *);
|
|
u32 i, n = va_arg (*va, u32);
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
unserialize_integer (m, &e[i].offset, sizeof (e[i].offset));
|
|
unserialize_integer (m, &e[i].next, sizeof (e[i].next));
|
|
unserialize_integer (m, &e[i].prev, sizeof (e[i].prev));
|
|
}
|
|
}
|
|
|
|
void
|
|
serialize_heap (serialize_main_t * m, va_list * va)
|
|
{
|
|
void *heap = va_arg (*va, void *);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
u32 i, l;
|
|
heap_header_t *h;
|
|
|
|
l = vec_len (heap);
|
|
serialize_integer (m, l, sizeof (u32));
|
|
if (l == 0)
|
|
return;
|
|
|
|
h = heap_header (heap);
|
|
|
|
#define foreach_serialize_heap_header_integer \
|
|
_ (head) _ (tail) _ (used_count) _ (max_len) _ (flags) _ (elt_bytes)
|
|
|
|
#define _(f) serialize_integer (m, h->f, sizeof (h->f));
|
|
foreach_serialize_heap_header_integer;
|
|
#undef _
|
|
|
|
serialize_integer (m, vec_len (h->free_lists), sizeof (u32));
|
|
for (i = 0; i < vec_len (h->free_lists); i++)
|
|
vec_serialize (m, h->free_lists[i], serialize_vec_32);
|
|
|
|
vec_serialize (m, h->elts, serialize_vec_heap_elt);
|
|
vec_serialize (m, h->small_free_elt_free_index, serialize_vec_32);
|
|
vec_serialize (m, h->free_elts, serialize_vec_32);
|
|
|
|
/* Serialize data in heap. */
|
|
{
|
|
heap_elt_t *e, *end;
|
|
e = h->elts + h->head;
|
|
end = h->elts + h->tail;
|
|
while (1)
|
|
{
|
|
if (!heap_is_free (e))
|
|
{
|
|
void *v = heap + heap_offset (e) * h->elt_bytes;
|
|
u32 n = heap_elt_size (heap, e);
|
|
serialize (m, f, v, n);
|
|
}
|
|
if (e == end)
|
|
break;
|
|
e = heap_next (e);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
unserialize_heap (serialize_main_t * m, va_list * va)
|
|
{
|
|
void **result = va_arg (*va, void **);
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
u32 i, vl, fl;
|
|
heap_header_t h;
|
|
void *heap;
|
|
|
|
unserialize_integer (m, &vl, sizeof (u32));
|
|
if (vl == 0)
|
|
{
|
|
*result = 0;
|
|
return;
|
|
}
|
|
|
|
clib_memset (&h, 0, sizeof (h));
|
|
#define _(f) unserialize_integer (m, &h.f, sizeof (h.f));
|
|
foreach_serialize_heap_header_integer;
|
|
#undef _
|
|
|
|
unserialize_integer (m, &fl, sizeof (u32));
|
|
vec_resize (h.free_lists, fl);
|
|
|
|
for (i = 0; i < vec_len (h.free_lists); i++)
|
|
vec_unserialize (m, &h.free_lists[i], unserialize_vec_32);
|
|
|
|
vec_unserialize (m, &h.elts, unserialize_vec_heap_elt);
|
|
vec_unserialize (m, &h.small_free_elt_free_index, unserialize_vec_32);
|
|
vec_unserialize (m, &h.free_elts, unserialize_vec_32);
|
|
|
|
/* Re-construct used elt bitmap. */
|
|
if (CLIB_DEBUG > 0)
|
|
{
|
|
heap_elt_t *e;
|
|
vec_foreach (e, h.elts)
|
|
{
|
|
if (!heap_is_free (e))
|
|
h.used_elt_bitmap = clib_bitmap_ori (h.used_elt_bitmap, e - h.elts);
|
|
}
|
|
}
|
|
|
|
heap = *result = _heap_new (vl, h.elt_bytes);
|
|
heap_header (heap)[0] = h;
|
|
|
|
/* Unserialize data in heap. */
|
|
{
|
|
heap_elt_t *e, *end;
|
|
e = h.elts + h.head;
|
|
end = h.elts + h.tail;
|
|
while (1)
|
|
{
|
|
if (!heap_is_free (e))
|
|
{
|
|
void *v = heap + heap_offset (e) * h.elt_bytes;
|
|
u32 n = heap_elt_size (heap, e);
|
|
unserialize (m, f, v, n);
|
|
}
|
|
if (e == end)
|
|
break;
|
|
e = heap_next (e);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
serialize_magic (serialize_main_t * m, void *magic, u32 magic_bytes)
|
|
{
|
|
void *p;
|
|
serialize_integer (m, magic_bytes, sizeof (magic_bytes));
|
|
p = serialize_get (m, magic_bytes);
|
|
clib_memcpy_fast (p, magic, magic_bytes);
|
|
}
|
|
|
|
void
|
|
unserialize_check_magic (serialize_main_t * m, void *magic, u32 magic_bytes)
|
|
{
|
|
u32 l;
|
|
void *d;
|
|
|
|
unserialize_integer (m, &l, sizeof (l));
|
|
if (l != magic_bytes)
|
|
{
|
|
bad:
|
|
serialize_error_return (m, "bad magic number");
|
|
}
|
|
d = serialize_get (m, magic_bytes);
|
|
if (memcmp (magic, d, magic_bytes))
|
|
goto bad;
|
|
}
|
|
|
|
__clib_export clib_error_t *
|
|
va_serialize (serialize_main_t * sm, va_list * va)
|
|
{
|
|
serialize_main_header_t *m = &sm->header;
|
|
serialize_function_t *f = va_arg (*va, serialize_function_t *);
|
|
clib_error_t *error = 0;
|
|
|
|
m->recursion_level += 1;
|
|
if (m->recursion_level == 1)
|
|
{
|
|
uword r = clib_setjmp (&m->error_longjmp, 0);
|
|
error = uword_to_pointer (r, clib_error_t *);
|
|
}
|
|
|
|
if (!error)
|
|
f (sm, va);
|
|
|
|
m->recursion_level -= 1;
|
|
return error;
|
|
}
|
|
|
|
__clib_export clib_error_t *
|
|
serialize (serialize_main_t * m, ...)
|
|
{
|
|
clib_error_t *error;
|
|
va_list va;
|
|
|
|
va_start (va, m);
|
|
error = va_serialize (m, &va);
|
|
va_end (va);
|
|
return error;
|
|
}
|
|
|
|
__clib_export clib_error_t *
|
|
unserialize (serialize_main_t * m, ...)
|
|
{
|
|
clib_error_t *error;
|
|
va_list va;
|
|
|
|
va_start (va, m);
|
|
error = va_serialize (m, &va);
|
|
va_end (va);
|
|
return error;
|
|
}
|
|
|
|
static void *
|
|
serialize_write_not_inline (serialize_main_header_t * m,
|
|
serialize_stream_t * s,
|
|
uword n_bytes_to_write, uword flags)
|
|
{
|
|
uword cur_bi, n_left_b, n_left_o;
|
|
|
|
ASSERT (s->current_buffer_index <= s->n_buffer_bytes);
|
|
cur_bi = s->current_buffer_index;
|
|
n_left_b = s->n_buffer_bytes - cur_bi;
|
|
n_left_o = vec_len (s->overflow_buffer);
|
|
|
|
/* Prepend overflow buffer if present. */
|
|
do
|
|
{
|
|
if (n_left_o > 0 && n_left_b > 0)
|
|
{
|
|
uword n = clib_min (n_left_b, n_left_o);
|
|
clib_memcpy_fast (s->buffer + cur_bi, s->overflow_buffer, n);
|
|
cur_bi += n;
|
|
n_left_b -= n;
|
|
n_left_o -= n;
|
|
if (n_left_o == 0)
|
|
_vec_len (s->overflow_buffer) = 0;
|
|
else
|
|
vec_delete (s->overflow_buffer, n, 0);
|
|
}
|
|
|
|
/* Call data function when buffer is complete. Data function should
|
|
dispatch with current buffer and give us a new one to write more
|
|
data into. */
|
|
if (n_left_b == 0)
|
|
{
|
|
s->current_buffer_index = cur_bi;
|
|
m->data_function (m, s);
|
|
cur_bi = s->current_buffer_index;
|
|
n_left_b = s->n_buffer_bytes - cur_bi;
|
|
}
|
|
}
|
|
while (n_left_o > 0);
|
|
|
|
if (n_left_o > 0 || n_left_b < n_bytes_to_write)
|
|
{
|
|
u8 *r;
|
|
vec_add2 (s->overflow_buffer, r, n_bytes_to_write);
|
|
return r;
|
|
}
|
|
else
|
|
{
|
|
s->current_buffer_index = cur_bi + n_bytes_to_write;
|
|
return s->buffer + cur_bi;
|
|
}
|
|
}
|
|
|
|
static void *
|
|
serialize_read_not_inline (serialize_main_header_t * m,
|
|
serialize_stream_t * s,
|
|
uword n_bytes_to_read, uword flags)
|
|
{
|
|
uword cur_bi, cur_oi, n_left_b, n_left_o, n_left_to_read;
|
|
|
|
ASSERT (s->current_buffer_index <= s->n_buffer_bytes);
|
|
|
|
cur_bi = s->current_buffer_index;
|
|
cur_oi = s->current_overflow_index;
|
|
|
|
n_left_b = s->n_buffer_bytes - cur_bi;
|
|
n_left_o = vec_len (s->overflow_buffer) - cur_oi;
|
|
|
|
/* Read from overflow? */
|
|
if (n_left_o >= n_bytes_to_read)
|
|
{
|
|
s->current_overflow_index = cur_oi + n_bytes_to_read;
|
|
return vec_elt_at_index (s->overflow_buffer, cur_oi);
|
|
}
|
|
|
|
/* Reset overflow buffer. */
|
|
if (n_left_o == 0 && s->overflow_buffer)
|
|
{
|
|
s->current_overflow_index = 0;
|
|
_vec_len (s->overflow_buffer) = 0;
|
|
}
|
|
|
|
n_left_to_read = n_bytes_to_read;
|
|
while (n_left_to_read > 0)
|
|
{
|
|
uword n;
|
|
|
|
/* If we don't have enough data between overflow and normal buffer
|
|
call read function. */
|
|
if (n_left_o + n_left_b < n_bytes_to_read)
|
|
{
|
|
/* Save any left over buffer in overflow vector. */
|
|
if (n_left_b > 0)
|
|
{
|
|
vec_add (s->overflow_buffer, s->buffer + cur_bi, n_left_b);
|
|
n_left_o += n_left_b;
|
|
n_left_to_read -= n_left_b;
|
|
/* Advance buffer to end --- even if
|
|
SERIALIZE_FLAG_NO_ADVANCE_CURRENT_BUFFER_INDEX is set. */
|
|
cur_bi = s->n_buffer_bytes;
|
|
n_left_b = 0;
|
|
}
|
|
|
|
if (m->data_function)
|
|
{
|
|
m->data_function (m, s);
|
|
cur_bi = s->current_buffer_index;
|
|
n_left_b = s->n_buffer_bytes - cur_bi;
|
|
}
|
|
}
|
|
|
|
/* For first time through loop return if we have enough data
|
|
in normal buffer and overflow vector is empty. */
|
|
if (n_left_o == 0
|
|
&& n_left_to_read == n_bytes_to_read && n_left_b >= n_left_to_read)
|
|
{
|
|
s->current_buffer_index = cur_bi + n_bytes_to_read;
|
|
return s->buffer + cur_bi;
|
|
}
|
|
|
|
if (!m->data_function || serialize_stream_is_end_of_stream (s))
|
|
{
|
|
/* This can happen for a peek at end of file.
|
|
Pad overflow buffer with 0s. */
|
|
vec_resize (s->overflow_buffer, n_left_to_read);
|
|
n_left_o += n_left_to_read;
|
|
n_left_to_read = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Copy from buffer to overflow vector. */
|
|
n = clib_min (n_left_to_read, n_left_b);
|
|
vec_add (s->overflow_buffer, s->buffer + cur_bi, n);
|
|
cur_bi += n;
|
|
n_left_b -= n;
|
|
n_left_o += n;
|
|
n_left_to_read -= n;
|
|
}
|
|
}
|
|
|
|
s->current_buffer_index = cur_bi;
|
|
s->current_overflow_index = cur_oi + n_bytes_to_read;
|
|
return vec_elt_at_index (s->overflow_buffer, cur_oi);
|
|
}
|
|
|
|
__clib_export void *
|
|
serialize_read_write_not_inline (serialize_main_header_t * m,
|
|
serialize_stream_t * s,
|
|
uword n_bytes, uword flags)
|
|
{
|
|
return (((flags & SERIALIZE_FLAG_IS_READ) ? serialize_read_not_inline :
|
|
serialize_write_not_inline) (m, s, n_bytes, flags));
|
|
}
|
|
|
|
static void
|
|
serialize_read_write_close (serialize_main_header_t * m,
|
|
serialize_stream_t * s, uword flags)
|
|
{
|
|
if (serialize_stream_is_end_of_stream (s))
|
|
return;
|
|
|
|
if (flags & SERIALIZE_FLAG_IS_WRITE)
|
|
/* "Write" 0 bytes to flush overflow vector. */
|
|
serialize_write_not_inline (m, s, /* n bytes */ 0, flags);
|
|
|
|
serialize_stream_set_end_of_stream (s);
|
|
|
|
/* Call it one last time to flush buffer and close. */
|
|
m->data_function (m, s);
|
|
|
|
vec_free (s->overflow_buffer);
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_close (serialize_main_t * m)
|
|
{
|
|
serialize_read_write_close (&m->header, &m->stream,
|
|
SERIALIZE_FLAG_IS_WRITE);
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_close (serialize_main_t * m)
|
|
{
|
|
serialize_read_write_close (&m->header, &m->stream, SERIALIZE_FLAG_IS_READ);
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes)
|
|
{
|
|
clib_memset (m, 0, sizeof (m[0]));
|
|
m->stream.buffer = data;
|
|
m->stream.n_buffer_bytes = n_data_bytes;
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes)
|
|
{
|
|
serialize_open_data (m, data, n_data_bytes);
|
|
}
|
|
|
|
static void
|
|
serialize_vector_write (serialize_main_header_t * m, serialize_stream_t * s)
|
|
{
|
|
if (!serialize_stream_is_end_of_stream (s))
|
|
{
|
|
/* Double buffer size. */
|
|
uword l = vec_len (s->buffer);
|
|
vec_resize (s->buffer, l > 0 ? l : 64);
|
|
s->n_buffer_bytes = vec_len (s->buffer);
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_open_vector (serialize_main_t * m, u8 * vector)
|
|
{
|
|
clib_memset (m, 0, sizeof (m[0]));
|
|
m->header.data_function = serialize_vector_write;
|
|
m->stream.buffer = vector;
|
|
m->stream.current_buffer_index = 0;
|
|
m->stream.n_buffer_bytes = vec_len (vector);
|
|
}
|
|
|
|
__clib_export void *
|
|
serialize_close_vector (serialize_main_t * m)
|
|
{
|
|
serialize_stream_t *s = &m->stream;
|
|
void *result;
|
|
|
|
serialize_close (m); /* frees overflow buffer */
|
|
|
|
if (s->buffer)
|
|
_vec_len (s->buffer) = s->current_buffer_index;
|
|
result = s->buffer;
|
|
clib_memset (m, 0, sizeof (m[0]));
|
|
return result;
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_multiple_1 (serialize_main_t *m, void *data, uword data_stride,
|
|
uword n_data)
|
|
{
|
|
u8 *d = data;
|
|
u8 *p;
|
|
uword n_left = n_data;
|
|
|
|
while (n_left >= 4)
|
|
{
|
|
p = serialize_get (m, 4 * sizeof (d[0]));
|
|
p[0] = d[0 * data_stride];
|
|
p[1] = d[1 * data_stride];
|
|
p[2] = d[2 * data_stride];
|
|
p[3] = d[3 * data_stride];
|
|
n_left -= 4;
|
|
d += 4 * data_stride;
|
|
}
|
|
|
|
if (n_left > 0)
|
|
{
|
|
p = serialize_get (m, n_left * sizeof (p[0]));
|
|
while (n_left > 0)
|
|
{
|
|
p[0] = d[0];
|
|
p += 1;
|
|
d += 1 * data_stride;
|
|
n_left -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_multiple_2 (serialize_main_t *m, void *data, uword data_stride,
|
|
uword n_data)
|
|
{
|
|
void *d = data;
|
|
u16 *p;
|
|
uword n_left = n_data;
|
|
|
|
while (n_left >= 4)
|
|
{
|
|
p = serialize_get (m, 4 * sizeof (p[0]));
|
|
clib_mem_unaligned (p + 0, u16) =
|
|
clib_host_to_net_mem_u16 (d + 0 * data_stride);
|
|
clib_mem_unaligned (p + 1, u16) =
|
|
clib_host_to_net_mem_u16 (d + 1 * data_stride);
|
|
clib_mem_unaligned (p + 2, u16) =
|
|
clib_host_to_net_mem_u16 (d + 2 * data_stride);
|
|
clib_mem_unaligned (p + 3, u16) =
|
|
clib_host_to_net_mem_u16 (d + 3 * data_stride);
|
|
n_left -= 4;
|
|
d += 4 * data_stride;
|
|
}
|
|
|
|
if (n_left > 0)
|
|
{
|
|
p = serialize_get (m, n_left * sizeof (p[0]));
|
|
while (n_left > 0)
|
|
{
|
|
clib_mem_unaligned (p + 0, u16) =
|
|
clib_host_to_net_mem_u16 (d + 0 * data_stride);
|
|
p += 1;
|
|
d += 1 * data_stride;
|
|
n_left -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_multiple_4 (serialize_main_t *m, void *data, uword data_stride,
|
|
uword n_data)
|
|
{
|
|
void *d = data;
|
|
u32 *p;
|
|
uword n_left = n_data;
|
|
|
|
while (n_left >= 4)
|
|
{
|
|
p = serialize_get (m, 4 * sizeof (p[0]));
|
|
clib_mem_unaligned (p + 0, u32) =
|
|
clib_host_to_net_mem_u32 (d + 0 * data_stride);
|
|
clib_mem_unaligned (p + 1, u32) =
|
|
clib_host_to_net_mem_u32 (d + 1 * data_stride);
|
|
clib_mem_unaligned (p + 2, u32) =
|
|
clib_host_to_net_mem_u32 (d + 2 * data_stride);
|
|
clib_mem_unaligned (p + 3, u32) =
|
|
clib_host_to_net_mem_u32 (d + 3 * data_stride);
|
|
n_left -= 4;
|
|
d += 4 * data_stride;
|
|
}
|
|
|
|
if (n_left > 0)
|
|
{
|
|
p = serialize_get (m, n_left * sizeof (p[0]));
|
|
while (n_left > 0)
|
|
{
|
|
clib_mem_unaligned (p + 0, u32) =
|
|
clib_host_to_net_mem_u32 (d + 0 * data_stride);
|
|
p += 1;
|
|
d += 1 * data_stride;
|
|
n_left -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_multiple_1 (serialize_main_t *m, void *data, uword data_stride,
|
|
uword n_data)
|
|
{
|
|
u8 *d = data;
|
|
u8 *p;
|
|
uword n_left = n_data;
|
|
|
|
while (n_left >= 4)
|
|
{
|
|
p = unserialize_get (m, 4 * sizeof (d[0]));
|
|
d[0 * data_stride] = p[0];
|
|
d[1 * data_stride] = p[1];
|
|
d[2 * data_stride] = p[2];
|
|
d[3 * data_stride] = p[3];
|
|
n_left -= 4;
|
|
d += 4 * data_stride;
|
|
}
|
|
|
|
if (n_left > 0)
|
|
{
|
|
p = unserialize_get (m, n_left * sizeof (p[0]));
|
|
while (n_left > 0)
|
|
{
|
|
d[0] = p[0];
|
|
p += 1;
|
|
d += 1 * data_stride;
|
|
n_left -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_multiple_2 (serialize_main_t *m, void *data, uword data_stride,
|
|
uword n_data)
|
|
{
|
|
void *d = data;
|
|
u16 *p;
|
|
uword n_left = n_data;
|
|
|
|
while (n_left >= 4)
|
|
{
|
|
p = unserialize_get (m, 4 * sizeof (p[0]));
|
|
clib_mem_unaligned (d + 0 * data_stride, u16) =
|
|
clib_net_to_host_mem_u16 (p + 0);
|
|
clib_mem_unaligned (d + 1 * data_stride, u16) =
|
|
clib_net_to_host_mem_u16 (p + 1);
|
|
clib_mem_unaligned (d + 2 * data_stride, u16) =
|
|
clib_net_to_host_mem_u16 (p + 2);
|
|
clib_mem_unaligned (d + 3 * data_stride, u16) =
|
|
clib_net_to_host_mem_u16 (p + 3);
|
|
n_left -= 4;
|
|
d += 4 * data_stride;
|
|
}
|
|
|
|
if (n_left > 0)
|
|
{
|
|
p = unserialize_get (m, n_left * sizeof (p[0]));
|
|
while (n_left > 0)
|
|
{
|
|
clib_mem_unaligned (d + 0 * data_stride, u16) =
|
|
clib_net_to_host_mem_u16 (p + 0);
|
|
p += 1;
|
|
d += 1 * data_stride;
|
|
n_left -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_multiple_4 (serialize_main_t *m, void *data, uword data_stride,
|
|
uword n_data)
|
|
{
|
|
void *d = data;
|
|
u32 *p;
|
|
uword n_left = n_data;
|
|
|
|
while (n_left >= 4)
|
|
{
|
|
p = unserialize_get (m, 4 * sizeof (p[0]));
|
|
clib_mem_unaligned (d + 0 * data_stride, u32) =
|
|
clib_net_to_host_mem_u32 (p + 0);
|
|
clib_mem_unaligned (d + 1 * data_stride, u32) =
|
|
clib_net_to_host_mem_u32 (p + 1);
|
|
clib_mem_unaligned (d + 2 * data_stride, u32) =
|
|
clib_net_to_host_mem_u32 (p + 2);
|
|
clib_mem_unaligned (d + 3 * data_stride, u32) =
|
|
clib_net_to_host_mem_u32 (p + 3);
|
|
n_left -= 4;
|
|
d += 4 * data_stride;
|
|
}
|
|
|
|
if (n_left > 0)
|
|
{
|
|
p = unserialize_get (m, n_left * sizeof (p[0]));
|
|
while (n_left > 0)
|
|
{
|
|
clib_mem_unaligned (d + 0 * data_stride, u32) =
|
|
clib_net_to_host_mem_u32 (p + 0);
|
|
p += 1;
|
|
d += 1 * data_stride;
|
|
n_left -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CLIB_UNIX
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
static void
|
|
clib_file_write (serialize_main_header_t * m, serialize_stream_t * s)
|
|
{
|
|
int fd, n;
|
|
|
|
fd = s->data_function_opaque;
|
|
n = write (fd, s->buffer, s->current_buffer_index);
|
|
if (n < 0)
|
|
{
|
|
if (!unix_error_is_fatal (errno))
|
|
n = 0;
|
|
else
|
|
serialize_error (m, clib_error_return_unix (0, "write"));
|
|
}
|
|
if (n == s->current_buffer_index)
|
|
_vec_len (s->buffer) = 0;
|
|
else
|
|
vec_delete (s->buffer, n, 0);
|
|
s->current_buffer_index = vec_len (s->buffer);
|
|
}
|
|
|
|
static void
|
|
clib_file_read (serialize_main_header_t * m, serialize_stream_t * s)
|
|
{
|
|
int fd, n;
|
|
|
|
fd = s->data_function_opaque;
|
|
n = read (fd, s->buffer, vec_len (s->buffer));
|
|
if (n < 0)
|
|
{
|
|
if (!unix_error_is_fatal (errno))
|
|
n = 0;
|
|
else
|
|
serialize_error (m, clib_error_return_unix (0, "read"));
|
|
}
|
|
else if (n == 0)
|
|
serialize_stream_set_end_of_stream (s);
|
|
s->current_buffer_index = 0;
|
|
s->n_buffer_bytes = n;
|
|
}
|
|
|
|
static void
|
|
serialize_open_clib_file_descriptor_helper (serialize_main_t * m, int fd,
|
|
uword is_read)
|
|
{
|
|
clib_memset (m, 0, sizeof (m[0]));
|
|
vec_resize (m->stream.buffer, 4096);
|
|
|
|
if (!is_read)
|
|
{
|
|
m->stream.n_buffer_bytes = vec_len (m->stream.buffer);
|
|
_vec_len (m->stream.buffer) = 0;
|
|
}
|
|
|
|
m->header.data_function = is_read ? clib_file_read : clib_file_write;
|
|
m->stream.data_function_opaque = fd;
|
|
}
|
|
|
|
__clib_export void
|
|
serialize_open_clib_file_descriptor (serialize_main_t * m, int fd)
|
|
{
|
|
serialize_open_clib_file_descriptor_helper (m, fd, /* is_read */ 0);
|
|
}
|
|
|
|
__clib_export void
|
|
unserialize_open_clib_file_descriptor (serialize_main_t * m, int fd)
|
|
{
|
|
serialize_open_clib_file_descriptor_helper (m, fd, /* is_read */ 1);
|
|
}
|
|
|
|
static clib_error_t *
|
|
serialize_open_clib_file_helper (serialize_main_t * m, char *file,
|
|
uword is_read)
|
|
{
|
|
int fd, mode;
|
|
|
|
mode = is_read ? O_RDONLY : O_RDWR | O_CREAT | O_TRUNC;
|
|
fd = open (file, mode, 0666);
|
|
if (fd < 0)
|
|
return clib_error_return_unix (0, "open `%s'", file);
|
|
|
|
serialize_open_clib_file_descriptor_helper (m, fd, is_read);
|
|
return 0;
|
|
}
|
|
|
|
__clib_export clib_error_t *
|
|
serialize_open_clib_file (serialize_main_t * m, char *file)
|
|
{
|
|
return serialize_open_clib_file_helper (m, file, /* is_read */ 0);
|
|
}
|
|
|
|
__clib_export clib_error_t *
|
|
unserialize_open_clib_file (serialize_main_t * m, char *file)
|
|
{
|
|
return serialize_open_clib_file_helper (m, file, /* is_read */ 1);
|
|
}
|
|
|
|
#endif /* CLIB_UNIX */
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|