qpb: Add support for protobuf.
Infrastructure that allows protocol buffers to be used in Quagga. The
changes below comprise of:
- Build hooks
- Protobuf definitions for common types.
- Library routines for working with protobuf, including functions
that help translate between common quagga types and their protobuf
equivalents.
Changes:
* qpb/{Makefile.am,README.txt,qpb.h,.gitignore}
Add the qpb library, which provides shared code and definitions
for using protocol buffers in quagga code.
* qpb/qpb.proto
Protobuf definitions that can be shared by all of quagga.
* qpb/linear_allocator.h
An allocator that allocates memory by walking down towards the end
of a buffer. This is used to cheaply allocate/deallocate memory on
the stack for protobuf operations.
* qpb/qpb_allocator.[ch]
Thin layer that allows a linear allocator to be used with the
protobuf-c library.
* common.am
This is an automake fragment that is intended to be shared by
Makefile.am files in the tree. It currently includes definitions
related to protobuf.
* configure.ac
- Add logic to optionally build protobuf code.
By default, protobuf support is enabled if the protobuf C
compiler (protoc-c) is available, and the associated header
files/library can be found.
The user can choose to override this behavior via the new
--disable-protobuf/--enable-protobuf flags.
- Include the quagga protobuf library (qpb) in the build.
* .gitignore
Ignore source code generated by protobuf compiler.
* Makefile.am
Add 'qpb' to the list of subdirectories.
Signed-off-by: Avneesh Sachdev <avneesh@sproute.com>
Edited: Paul Jakma <paul.jakma@hpe.com>: Change the sense of the
configure enable option to require explicit specifying, as
an experimental feature.
diff --git a/qpb/linear_allocator.h b/qpb/linear_allocator.h
new file mode 100644
index 0000000..e3ebbc6
--- /dev/null
+++ b/qpb/linear_allocator.h
@@ -0,0 +1,207 @@
+/*
+ * linear_allocator.h
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ *
+ * This file is part of Quagga.
+ *
+ * Quagga is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * Quagga is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Quagga; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+/*
+ * Header file for the linear allocator.
+ *
+ * An allocator that allocates memory by walking down towards the end
+ * of a buffer. No attempt is made to reuse blocks that are freed
+ * subsequently. The assumption is that the buffer is big enough to
+ * cover allocations for a given purpose.
+ */
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * Alignment for block allocated by the allocator. Must be a power of 2.
+ */
+#define LINEAR_ALLOCATOR_ALIGNMENT 8
+
+#define LINEAR_ALLOCATOR_ALIGN(value) \
+ (((value) + LINEAR_ALLOCATOR_ALIGNMENT - 1) & ~(LINEAR_ALLOCATOR_ALIGNMENT - 1));
+
+/*
+ * linear_allocator_align_ptr
+ */
+static inline char *
+linear_allocator_align_ptr (char *ptr)
+{
+ return (char *) LINEAR_ALLOCATOR_ALIGN ((intptr_t) ptr);
+}
+
+typedef struct linear_allocator_t_
+{
+ char *buf;
+
+ /*
+ * Current location in the buffer.
+ */
+ char *cur;
+
+ /*
+ * End of buffer.
+ */
+ char *end;
+
+ /*
+ * Version number of the allocator, this is bumped up when the allocator
+ * is reset and helps identifies bad frees.
+ */
+ uint32_t version;
+
+ /*
+ * The number of blocks that are currently allocated.
+ */
+ int num_allocated;
+} linear_allocator_t;
+
+/*
+ * linear_allocator_block_t
+ *
+ * Header structure at the begining of each block.
+ */
+typedef struct linear_allocator_block_t_
+{
+ uint32_t flags;
+
+ /*
+ * The version of the allocator when this block was allocated.
+ */
+ uint32_t version;
+ char data[0];
+} linear_allocator_block_t;
+
+#define LINEAR_ALLOCATOR_BLOCK_IN_USE 0x01
+
+#define LINEAR_ALLOCATOR_HDR_SIZE (sizeof(linear_allocator_block_t))
+
+/*
+ * linear_allocator_block_size
+ *
+ * The total amount of space a block will take in the buffer,
+ * including the size of the header.
+ */
+static inline size_t
+linear_allocator_block_size (size_t user_size)
+{
+ return LINEAR_ALLOCATOR_ALIGN (LINEAR_ALLOCATOR_HDR_SIZE + user_size);
+}
+
+/*
+ * linear_allocator_ptr_to_block
+ */
+static inline linear_allocator_block_t *
+linear_allocator_ptr_to_block (void *ptr)
+{
+ void *block_ptr;
+ block_ptr = ((char *) ptr) - offsetof (linear_allocator_block_t, data);
+ return block_ptr;
+}
+
+/*
+ * linear_allocator_init
+ */
+static inline void
+linear_allocator_init (linear_allocator_t * allocator, char *buf,
+ size_t buf_len)
+{
+ memset (allocator, 0, sizeof (*allocator));
+
+ assert (linear_allocator_align_ptr (buf) == buf);
+ allocator->buf = buf;
+ allocator->cur = buf;
+ allocator->end = buf + buf_len;
+}
+
+/*
+ * linear_allocator_reset
+ *
+ * Prepare an allocator for reuse.
+ *
+ * *** NOTE ** This implicitly frees all the blocks in the allocator.
+ */
+static inline void
+linear_allocator_reset (linear_allocator_t *allocator)
+{
+ allocator->num_allocated = 0;
+ allocator->version++;
+ allocator->cur = allocator->buf;
+}
+
+/*
+ * linear_allocator_alloc
+ */
+static inline void *
+linear_allocator_alloc (linear_allocator_t *allocator, size_t user_size)
+{
+ size_t block_size;
+ linear_allocator_block_t *block;
+
+ block_size = linear_allocator_block_size (user_size);
+
+ if (allocator->cur + block_size > allocator->end)
+ {
+ return NULL;
+ }
+
+ block = (linear_allocator_block_t *) allocator->cur;
+ allocator->cur += block_size;
+
+ block->flags = LINEAR_ALLOCATOR_BLOCK_IN_USE;
+ block->version = allocator->version;
+ allocator->num_allocated++;
+ return block->data;
+}
+
+/*
+ * linear_allocator_free
+ */
+static inline void
+linear_allocator_free (linear_allocator_t *allocator, void *ptr)
+{
+ linear_allocator_block_t *block;
+
+ if (((char *) ptr) < allocator->buf || ((char *) ptr) >= allocator->end)
+ {
+ assert (0);
+ return;
+ }
+
+ block = linear_allocator_ptr_to_block (ptr);
+ if (block->version != allocator->version)
+ {
+ assert (0);
+ return;
+ }
+
+ block->flags = block->flags & ~LINEAR_ALLOCATOR_BLOCK_IN_USE;
+
+ if (--allocator->num_allocated < 0)
+ {
+ assert (0);
+ }
+}