diff options
Diffstat (limited to 'src/vppinfra/serialize.c')
-rw-r--r-- | src/vppinfra/serialize.c | 1254 |
1 files changed, 1254 insertions, 0 deletions
diff --git a/src/vppinfra/serialize.c b/src/vppinfra/serialize.c new file mode 100644 index 00000000000..5d401a080c1 --- /dev/null +++ b/src/vppinfra/serialize.c @@ -0,0 +1,1254 @@ +/* + * 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; +} + +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 (p, s, len); + } +} + +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 (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 (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 (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 + +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 (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); +} + +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 (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; + } + + 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 (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_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_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_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 (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); +} + +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); +} + +void +serialize_close (serialize_main_t * m) +{ + serialize_read_write_close (&m->header, &m->stream, + SERIALIZE_FLAG_IS_WRITE); +} + +void +unserialize_close (serialize_main_t * m) +{ + serialize_read_write_close (&m->header, &m->stream, SERIALIZE_FLAG_IS_READ); +} + +void +serialize_open_data (serialize_main_t * m, u8 * data, uword n_data_bytes) +{ + memset (m, 0, sizeof (m[0])); + m->stream.buffer = data; + m->stream.n_buffer_bytes = n_data_bytes; +} + +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); + } +} + +void +serialize_open_vector (serialize_main_t * m, u8 * vector) +{ + 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); +} + +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; + memset (m, 0, sizeof (m[0])); + return result; +} + +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; + } + } +} + +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; + } + } +} + +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; + } + } +} + +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; + } + } +} + +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; + } + } +} + +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 +unix_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 +unix_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_unix_file_descriptor_helper (serialize_main_t * m, int fd, + uword is_read) +{ + 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 ? unix_file_read : unix_file_write; + m->stream.data_function_opaque = fd; +} + +void +serialize_open_unix_file_descriptor (serialize_main_t * m, int fd) +{ + serialize_open_unix_file_descriptor_helper (m, fd, /* is_read */ 0); +} + +void +unserialize_open_unix_file_descriptor (serialize_main_t * m, int fd) +{ + serialize_open_unix_file_descriptor_helper (m, fd, /* is_read */ 1); +} + +static clib_error_t * +serialize_open_unix_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_unix_file_descriptor_helper (m, fd, is_read); + return 0; +} + +clib_error_t * +serialize_open_unix_file (serialize_main_t * m, char *file) +{ + return serialize_open_unix_file_helper (m, file, /* is_read */ 0); +} + +clib_error_t * +unserialize_open_unix_file (serialize_main_t * m, char *file) +{ + return serialize_open_unix_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: + */ |