summaryrefslogtreecommitdiffstats
path: root/qpb
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
commite2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch)
treef0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /qpb
parentInitial commit. (diff)
downloadfrr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz
frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'qpb')
-rw-r--r--qpb/Makefile10
-rw-r--r--qpb/README.txt1
-rw-r--r--qpb/linear_allocator.h181
-rw-r--r--qpb/qpb.c12
-rw-r--r--qpb/qpb.h351
-rw-r--r--qpb/qpb.proto93
-rw-r--r--qpb/qpb_allocator.c46
-rw-r--r--qpb/qpb_allocator.h91
-rw-r--r--qpb/subdir.am31
9 files changed, 816 insertions, 0 deletions
diff --git a/qpb/Makefile b/qpb/Makefile
new file mode 100644
index 0000000..2237def
--- /dev/null
+++ b/qpb/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. fpm/libfrr_pb.la
+%: ALWAYS
+ @$(MAKE) -s -C .. fpm/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/qpb/README.txt b/qpb/README.txt
new file mode 100644
index 0000000..7a09452
--- /dev/null
+++ b/qpb/README.txt
@@ -0,0 +1 @@
+Protobuf definitions and code that is applicable to all of Quagga/FRR.
diff --git a/qpb/linear_allocator.h b/qpb/linear_allocator.h
new file mode 100644
index 0000000..352d3ea
--- /dev/null
+++ b/qpb/linear_allocator.h
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linear_allocator.h
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ */
+
+/*
+ * 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);
+ }
+}
diff --git a/qpb/qpb.c b/qpb/qpb.c
new file mode 100644
index 0000000..63454f1
--- /dev/null
+++ b/qpb/qpb.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * qpb.c
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ */
+
+/*
+ * Main file for the qpb library.
+ */
diff --git a/qpb/qpb.h b/qpb/qpb.h
new file mode 100644
index 0000000..d52528f
--- /dev/null
+++ b/qpb/qpb.h
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * qpb.h
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ */
+
+/*
+ * Main public header file for the quagga protobuf library.
+ */
+
+#ifndef _QPB_H
+#define _QPB_H
+
+#include "prefix.h"
+
+#include "qpb/qpb.pb-c.h"
+
+#include "qpb/qpb_allocator.h"
+
+/*
+ * qpb__address_family__set
+ */
+#define qpb_address_family_set qpb__address_family__set
+static inline int qpb__address_family__set(Qpb__AddressFamily *pb_family,
+ uint8_t family)
+{
+ switch (family) {
+ case AF_INET:
+ *pb_family = QPB__ADDRESS_FAMILY__IPV4;
+ return 1;
+
+ case AF_INET6:
+ *pb_family = QPB__ADDRESS_FAMILY__IPV6;
+ return 1;
+
+ default:
+ *pb_family = QPB__ADDRESS_FAMILY__UNKNOWN_AF;
+ }
+
+ return 0;
+}
+
+/*
+ * qpb__address_family__get
+ */
+#define qpb_address_family_get qpb__address_family__get
+static inline int qpb__address_family__get(Qpb__AddressFamily pb_family,
+ uint8_t *family)
+{
+
+ switch (pb_family) {
+ case QPB__ADDRESS_FAMILY__IPV4:
+ *family = AF_INET;
+ return 1;
+
+ case QPB__ADDRESS_FAMILY__IPV6:
+ *family = AF_INET6;
+ return 1;
+
+ case QPB__ADDRESS_FAMILY__UNKNOWN_AF:
+ return 0;
+ case _QPB__ADDRESS_FAMILY_IS_INT_SIZE:
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * qpb__l3_prefix__create
+ */
+#define qpb_l3_prefix_create qpb__l3_prefix__create
+static inline Qpb__L3Prefix *qpb__l3_prefix__create(qpb_allocator_t *allocator,
+ struct prefix *p)
+{
+ Qpb__L3Prefix *prefix;
+
+ prefix = QPB_ALLOC(allocator, typeof(*prefix));
+ if (!prefix) {
+ return NULL;
+ }
+ qpb__l3_prefix__init(prefix);
+ prefix->length = p->prefixlen;
+ prefix->bytes.len = (p->prefixlen + 7) / 8;
+ prefix->bytes.data = qpb_alloc(allocator, prefix->bytes.len);
+ if (!prefix->bytes.data) {
+ return NULL;
+ }
+
+ memcpy(prefix->bytes.data, &p->u.prefix, prefix->bytes.len);
+
+ return prefix;
+}
+
+/*
+ * qpb__l3_prefix__get
+ */
+#define qpb_l3_prefix_get qpb__l3_prefix__get
+static inline int qpb__l3_prefix__get(const Qpb__L3Prefix *pb_prefix,
+ uint8_t family, struct prefix *prefix)
+{
+
+ switch (family) {
+
+ case AF_INET:
+ memset((struct prefix_ipv4 *)prefix, 0,
+ sizeof(struct prefix_ipv4));
+ break;
+
+ case AF_INET6:
+ memset((struct prefix_ipv6 *)prefix, 0,
+ sizeof(struct prefix_ipv6));
+ break;
+
+ default:
+ memset(prefix, 0, sizeof(*prefix));
+ }
+
+ prefix->prefixlen = pb_prefix->length;
+ prefix->family = family;
+ memcpy(&prefix->u.prefix, pb_prefix->bytes.data, pb_prefix->bytes.len);
+ return 1;
+}
+
+/*
+ * qpb__protocol__set
+ *
+ * Translate a quagga route type to a protobuf protocol.
+ */
+#define qpb_protocol_set qpb__protocol__set
+static inline int qpb__protocol__set(Qpb__Protocol *pb_proto, int route_type)
+{
+ switch (route_type) {
+ case ZEBRA_ROUTE_KERNEL:
+ *pb_proto = QPB__PROTOCOL__KERNEL;
+ break;
+
+ case ZEBRA_ROUTE_CONNECT:
+ *pb_proto = QPB__PROTOCOL__CONNECTED;
+ break;
+
+ case ZEBRA_ROUTE_STATIC:
+ *pb_proto = QPB__PROTOCOL__STATIC;
+ break;
+
+ case ZEBRA_ROUTE_RIP:
+ *pb_proto = QPB__PROTOCOL__RIP;
+ break;
+
+ case ZEBRA_ROUTE_RIPNG:
+ *pb_proto = QPB__PROTOCOL__RIPNG;
+ break;
+
+ case ZEBRA_ROUTE_OSPF:
+ case ZEBRA_ROUTE_OSPF6:
+ *pb_proto = QPB__PROTOCOL__OSPF;
+ break;
+
+ case ZEBRA_ROUTE_ISIS:
+ *pb_proto = QPB__PROTOCOL__ISIS;
+ break;
+
+ case ZEBRA_ROUTE_BGP:
+ *pb_proto = QPB__PROTOCOL__BGP;
+ break;
+
+ case ZEBRA_ROUTE_HSLS:
+ case ZEBRA_ROUTE_OLSR:
+ case ZEBRA_ROUTE_MAX:
+ case ZEBRA_ROUTE_SYSTEM:
+ default:
+ *pb_proto = QPB__PROTOCOL__OTHER;
+ }
+
+ return 1;
+}
+
+/*
+ * qpb__ipv4_address__create
+ */
+static inline Qpb__Ipv4Address *
+qpb__ipv4_address__create(qpb_allocator_t *allocator, struct in_addr *addr)
+{
+ Qpb__Ipv4Address *v4;
+
+ v4 = QPB_ALLOC(allocator, typeof(*v4));
+ if (!v4) {
+ return NULL;
+ }
+ qpb__ipv4_address__init(v4);
+
+ v4->value = ntohl(addr->s_addr);
+ return v4;
+}
+
+/*
+ * qpb__ipv4_address__get
+ */
+static inline int qpb__ipv4_address__get(const Qpb__Ipv4Address *v4,
+ struct in_addr *addr)
+{
+ addr->s_addr = htonl(v4->value);
+ return 1;
+}
+
+/*
+ * qpb__ipv6_address__create
+ */
+static inline Qpb__Ipv6Address *
+qpb__ipv6_address__create(qpb_allocator_t *allocator, struct in6_addr *addr)
+{
+ Qpb__Ipv6Address *v6;
+
+ v6 = QPB_ALLOC(allocator, typeof(*v6));
+ if (!v6)
+ return NULL;
+
+ qpb__ipv6_address__init(v6);
+ v6->bytes.len = 16;
+ v6->bytes.data = qpb_alloc(allocator, 16);
+ if (!v6->bytes.data)
+ return NULL;
+
+ memcpy(v6->bytes.data, addr->s6_addr, v6->bytes.len);
+ return v6;
+}
+
+/*
+ * qpb__ipv6_address__get
+ *
+ * Read out information from a protobuf ipv6 address structure.
+ */
+static inline int qpb__ipv6_address__get(const Qpb__Ipv6Address *v6,
+ struct in6_addr *addr)
+{
+ if (v6->bytes.len != 16)
+ return 0;
+
+ memcpy(addr->s6_addr, v6->bytes.data, v6->bytes.len);
+ return 1;
+}
+
+/*
+ * qpb__l3_address__create
+ */
+#define qpb_l3_address_create qpb__l3_address__create
+static inline Qpb__L3Address *
+qpb__l3_address__create(qpb_allocator_t *allocator, union g_addr *addr,
+ uint8_t family)
+{
+ Qpb__L3Address *l3_addr;
+
+ l3_addr = QPB_ALLOC(allocator, typeof(*l3_addr));
+ if (!l3_addr)
+ return NULL;
+
+ qpb__l3_address__init(l3_addr);
+
+ switch (family) {
+
+ case AF_INET:
+ l3_addr->v4 = qpb__ipv4_address__create(allocator, &addr->ipv4);
+ if (!l3_addr->v4)
+ return NULL;
+
+ break;
+
+ case AF_INET6:
+ l3_addr->v6 = qpb__ipv6_address__create(allocator, &addr->ipv6);
+ if (!l3_addr->v6)
+ return NULL;
+
+ break;
+ }
+ return l3_addr;
+}
+
+/*
+ * qpb__l3_address__get
+ *
+ * Read out a gateway address from a protobuf l3 address.
+ */
+#define qpb_l3_address_get qpb__l3_address__get
+static inline int qpb__l3_address__get(const Qpb__L3Address *l3_addr,
+ uint8_t *family, union g_addr *addr)
+{
+ if (l3_addr->v4) {
+ qpb__ipv4_address__get(l3_addr->v4, &addr->ipv4);
+ *family = AF_INET;
+ return 1;
+ }
+
+ if (l3_addr->v6) {
+ qpb__ipv6_address__get(l3_addr->v6, &addr->ipv6);
+ *family = AF_INET6;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * qpb__if_identifier__create
+ */
+#define qpb_if_identifier_create qpb__if_identifier__create
+static inline Qpb__IfIdentifier *
+qpb__if_identifier__create(qpb_allocator_t *allocator, uint if_index)
+{
+ Qpb__IfIdentifier *if_id;
+
+ if_id = QPB_ALLOC(allocator, typeof(*if_id));
+ if (!if_id) {
+ return NULL;
+ }
+ qpb__if_identifier__init(if_id);
+ if_id->has_index = 1;
+ if_id->index = if_index;
+ return if_id;
+}
+
+/*
+ * qpb__if_identifier__get
+ *
+ * Get interface name and/or if_index from an if identifier.
+ */
+#define qpb_if_identifier_get qpb__if_identifier__get
+static inline int qpb__if_identifier__get(Qpb__IfIdentifier *if_id,
+ uint *if_index, char **name)
+{
+ char *str;
+ uint ix;
+
+ if (!if_index)
+ if_index = &ix;
+
+ if (!name)
+ name = &str;
+
+ if (if_id->has_index)
+ *if_index = if_id->index;
+ else
+ *if_index = 0;
+
+ *name = if_id->name;
+ return 1;
+}
+
+#endif
diff --git a/qpb/qpb.proto b/qpb/qpb.proto
new file mode 100644
index 0000000..b095368
--- /dev/null
+++ b/qpb/qpb.proto
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: ISC
+/*
+ * qpb.proto
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+syntax = "proto2";
+
+/*
+ * Protobuf definitions pertaining to the Quagga/FRR Protobuf component.
+ */
+package qpb;
+
+enum AddressFamily {
+ UNKNOWN_AF = 0;
+ IPV4 = 1; // IP version 4
+ IPV6 = 2; // IP version 6
+};
+
+enum SubAddressFamily {
+ UNKNOWN_SAF = 0;
+ UNICAST = 1;
+ MULTICAST = 2;
+};
+
+//
+// An IP version 4 address, such as 10.1.1.1.
+//
+message Ipv4Address {
+ required fixed32 value = 1 ;
+};
+
+message Ipv6Address {
+
+ // 16 bytes.
+ required bytes bytes = 1;
+};
+
+//
+// An IP version 4 or IP version 6 address.
+//
+message L3Address {
+ optional Ipv4Address v4 = 1;
+ optional Ipv6Address v6 = 2;
+};
+
+//
+// An IP prefix, such as 10.1/16.
+// We use the message below to represent both IPv4 and IPv6 prefixes.
+message L3Prefix {
+ required uint32 length = 1;
+ required bytes bytes = 2;
+};
+
+//
+// Something that identifies an interface on a machine. It can either
+// be a name (for instance, 'eth0') or a number currently.
+//
+message IfIdentifier {
+ optional uint32 index = 1;
+ optional string name = 2;
+};
+
+enum Protocol {
+ UNKNOWN_PROTO = 0;
+ LOCAL = 1;
+ CONNECTED = 2;
+ KERNEL = 3;
+ STATIC = 4;
+ RIP = 5;
+ RIPNG = 6;
+ OSPF = 7;
+ ISIS = 8;
+ BGP = 9;
+ OTHER = 10;
+}
diff --git a/qpb/qpb_allocator.c b/qpb/qpb_allocator.c
new file mode 100644
index 0000000..e2749d6
--- /dev/null
+++ b/qpb/qpb_allocator.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * qpb_allocator.c
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "linear_allocator.h"
+
+#include "qpb_allocator.h"
+
+/*
+ * _qpb_alloc
+ */
+static void *_qpb_alloc(void *allocator_data, size_t size)
+{
+ return linear_allocator_alloc(allocator_data, size);
+}
+
+/*
+ * _qpb_free
+ */
+static void _qpb_free(void *allocator_data, void *ptr)
+{
+ linear_allocator_free(allocator_data, ptr);
+}
+
+static ProtobufCAllocator allocator_template = {_qpb_alloc, _qpb_free, NULL};
+
+/*
+ * qpb_allocator_init_linear
+ *
+ * Initialize qpb_allocator_t with the given linear allocator.
+ */
+void qpb_allocator_init_linear(qpb_allocator_t *allocator,
+ linear_allocator_t *linear_allocator)
+{
+ *allocator = allocator_template;
+ allocator->allocator_data = linear_allocator;
+}
diff --git a/qpb/qpb_allocator.h b/qpb/qpb_allocator.h
new file mode 100644
index 0000000..ff0e466
--- /dev/null
+++ b/qpb/qpb_allocator.h
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * qpb_allocator.h
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ */
+
+/*
+ * Header file for Quagga/FRR protobuf memory management code.
+ */
+
+#ifndef _QPB_ALLOCATOR_H_
+#define _QPB_ALLOCATOR_H_
+
+#include <google/protobuf-c/protobuf-c.h>
+
+struct linear_allocator_t_;
+
+/*
+ * Alias for ProtobufCAllocator that is easier on the fingers.
+ */
+typedef ProtobufCAllocator qpb_allocator_t;
+
+/*
+ * qpb_alloc
+ */
+static inline void *qpb_alloc(qpb_allocator_t *allocator, size_t size)
+{
+ return allocator->alloc(allocator->allocator_data, size);
+}
+
+/*
+ * qpb_alloc_ptr_array
+ *
+ * Allocate space for the specified number of pointers.
+ */
+static inline void *qpb_alloc_ptr_array(qpb_allocator_t *allocator,
+ size_t num_ptrs)
+{
+ return qpb_alloc(allocator, num_ptrs * sizeof(void *));
+}
+
+/*
+ * qpb_free
+ */
+static inline void qpb_free(qpb_allocator_t *allocator, void *ptr)
+{
+ allocator->free(allocator->allocator_data, ptr);
+}
+
+/*
+ * QPB_ALLOC
+ *
+ * Convenience macro to reduce the probability of allocating memory of
+ * incorrect size. It returns enough memory to store the given type,
+ * and evaluates to an appropriately typed pointer.
+ */
+#define QPB_ALLOC(allocator, type) (type *)qpb_alloc(allocator, sizeof(type))
+
+/*
+ * Externs.
+ */
+extern void qpb_allocator_init_linear(qpb_allocator_t *,
+ struct linear_allocator_t_ *);
+
+/*
+ * The following macros are for the common case where a qpb allocator
+ * is being used alongside a linear allocator that allocates memory
+ * off of the stack.
+ */
+#define QPB_DECLARE_STACK_ALLOCATOR(allocator, size) \
+ qpb_allocator_t allocator; \
+ linear_allocator_t lin_##allocator; \
+ char lin_##allocator##_buf[size]
+
+#define QPB_INIT_STACK_ALLOCATOR(allocator) \
+ do { \
+ linear_allocator_init(&(lin_##allocator), \
+ lin_##allocator##_buf, \
+ sizeof(lin_##allocator##_buf)); \
+ qpb_allocator_init_linear(&allocator, &(lin_##allocator)); \
+ } while (0)
+
+#define QPB_RESET_STACK_ALLOCATOR(allocator) \
+ do { \
+ linear_allocator_reset(&(lin_##allocator)); \
+ } while (0)
+
+#endif /* _QPB_ALLOCATOR_H_ */
diff --git a/qpb/subdir.am b/qpb/subdir.am
new file mode 100644
index 0000000..21aa84d
--- /dev/null
+++ b/qpb/subdir.am
@@ -0,0 +1,31 @@
+if HAVE_PROTOBUF
+lib_LTLIBRARIES += qpb/libfrr_pb.la
+endif
+
+qpb_libfrr_pb_la_CPPFLAGS = $(AM_CPPFLAGS) $(PROTOBUF_C_CFLAGS)
+qpb_libfrr_pb_la_LIBADD = $(PROTOBUF_C_LIBS)
+qpb_libfrr_pb_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0
+
+qpb_libfrr_pb_la_SOURCES = \
+ qpb/qpb.c \
+ qpb/qpb_allocator.c \
+ # end
+
+if HAVE_PROTOBUF
+nodist_qpb_libfrr_pb_la_SOURCES = \
+ qpb/qpb.pb-c.c \
+ # end
+endif
+
+noinst_HEADERS += \
+ qpb/linear_allocator.h \
+ qpb/qpb.h \
+ qpb/qpb_allocator.h \
+ # end
+
+CLEANFILES += \
+ qpb/qpb.pb-c.c \
+ qpb/qpb.pb-c.h \
+ # end
+
+EXTRA_DIST += qpb/qpb.proto