Browse Source

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.
Avneesh Sachdev 3 years ago
parent
commit
07e5b64505
13 changed files with 1047 additions and 3 deletions
  1. 3 0
      .gitignore
  2. 2 2
      Makefile.am
  3. 41 0
      common.am
  4. 46 1
      configure.ac
  5. 15 0
      qpb/.gitignore
  6. 30 0
      qpb/Makefile.am
  7. 1 0
      qpb/README.txt
  8. 207 0
      qpb/linear_allocator.h
  9. 29 0
      qpb/qpb.c
  10. 372 0
      qpb/qpb.h
  11. 121 0
      qpb/qpb.proto
  12. 67 0
      qpb/qpb_allocator.c
  13. 113 0
      qpb/qpb_allocator.h

+ 3 - 0
.gitignore

@@ -38,3 +38,6 @@ build
 m4/*.m4
 !m4/ax_sys_weak_alias.m4
 cscope.*
+*.pb.h
+*.pb-c.h
+*.pb-c.c

+ 2 - 2
Makefile.am

@@ -1,10 +1,10 @@
 ## Process this file with automake to produce Makefile.in.
 
-SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
+SUBDIRS = lib qpb @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
          @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
          redhat @SOLARIS@ tests
 
-DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
+DIST_SUBDIRS = lib qpb zebra bgpd ripd ripngd ospfd ospf6d \
 	  isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
 	  solaris pimd
 

+ 41 - 0
common.am

@@ -0,0 +1,41 @@
+#
+# Automake fragment intended to be shared by Makefile.am files in the
+# tree.
+#
+
+if HAVE_PROTOBUF
+
+# Uncomment to use an non-system version of libprotobuf-c.
+#
+# Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src
+# Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la
+
+Q_PROTOBUF_C_CLIENT_INCLUDES=
+Q_PROTOBUF_C_CLIENT_LDOPTS=-lprotobuf-c
+
+Q_PROTOC=protoc
+Q_PROTOC_C=protoc-c
+
+Q_PROTOBUF_CFILES = $(filter %.pb-c.c,$(SOURCES))
+
+Q_PROTOBUF_SRCS = $(Q_PROTOBUF_CFILES) $(Q_PROTOBUF_HFILES)
+
+# Rules
+%.pb.h: %.proto
+	$(Q_PROTOC) $(PROTOBUF_INCLUDES) --cpp_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^
+
+%.pb-c.c %.pb-c.h: %.proto
+	$(Q_PROTOC_C) $(PROTOBUF_INCLUDES) --c_out=$(top_srcdir) $(top_srcdir)/$(PROTOBUF_PACKAGE)/$^
+
+#
+# Information about how to link to various libraries.
+#
+Q_QUAGGA_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libquagga_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS)
+
+Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfpm_pb.la $(Q_QUAGGA_PB_CLIENT_LDOPTS)
+
+endif  # HAVE_PROTOBUF
+
+Q_CLEANFILES = $(Q_PROTOBUF_SRCS)
+
+Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS)

+ 46 - 1
configure.ac

@@ -301,6 +301,8 @@ AC_ARG_ENABLE(fpm,
   AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support]))
 AC_ARG_ENABLE(werror,
   AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)]))
+AC_ARG_ENABLE([protobuf],
+  AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support]))
 
 if test x"${enable_gcc_rdynamic}" != x"no" ; then
   if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC"; then
@@ -320,6 +322,48 @@ if test "${enable_fpm}" = "yes"; then
    AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support)
 fi
 
+#
+# Logic for protobuf support.
+#
+if test "$enable_protobuf" = "yes"; then
+   have_protobuf=yes
+
+   # Check for protoc-c
+   AC_CHECK_PROG([PROTOC_C], [protoc-c], [protoc-c], [/bin/false])
+   if test "x$PROTOC_C" = "x/bin/false"; then
+      have_protobuf=no
+   else
+      found_protobuf_c=no
+      PKG_CHECK_MODULES([PROTOBUF_C], libprotobuf-c >= 0.14,
+                     [found_protobuf_c=yes],
+                     [AC_MSG_RESULT([pkg-config did not find libprotobuf-c])])
+
+      if test "x$found_protobuf_c" = "xyes"; then
+         LDFLAGS="$LDFLAGS $PROTOBUF_C_LIBS"
+         CFLAGS="$CFLAGS $PROTOBUF_C_CFLAGS"
+      else
+        AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h], [],
+                        [have_protobuf=no; AC_MSG_RESULT([Couldn't find google/protobuf-c.h])])
+      fi
+   fi
+fi
+
+# Fail if the user explicity enabled protobuf support and we couldn't
+# find the compiler or libraries.
+if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then
+   AC_MSG_ERROR([Protobuf enabled explicitly but can't find libraries/tools])
+fi
+
+if test "x$have_protobuf" = "xyes"; then
+   AC_DEFINE(HAVE_PROTOBUF,, protobuf)
+fi
+
+AM_CONDITIONAL([HAVE_PROTOBUF], [test "x$have_protobuf" = "xyes"])
+
+#
+# End of logic for protobuf support.
+#
+
 if test "${enable_tcp_zebra}" = "yes"; then
   AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication)
 fi
@@ -1530,7 +1574,7 @@ AC_CACHE_VAL(ac_cv_htonl_works,
 )
 AC_MSG_RESULT($ac_cv_htonl_works)
 
-AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile 
+AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile 
 	  ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile
 	  ospf6d/Makefile isisd/Makefile vtysh/Makefile
 	  doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
@@ -1570,6 +1614,7 @@ group to run as		: ${enable_group}
 group for vty sockets	: ${enable_vty_group}
 config file mask        : ${enable_configfile_mask}
 log file mask           : ${enable_logfile_mask}
+zebra protobuf enabled  : ${have_protobuf:-no}
 
 The above user and group must have read/write access to the state file
 directory and to the config files in the config file directory."

+ 15 - 0
qpb/.gitignore

@@ -0,0 +1,15 @@
+Makefile
+Makefile.in
+*.o
+tags
+TAGS
+.deps
+.nfs*
+*.lo
+*.la
+*.a
+*.libs
+.arch-inventory
+.arch-ids
+*~
+*.loT

+ 30 - 0
qpb/Makefile.am

@@ -0,0 +1,30 @@
+include ../common.am
+
+AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib $(Q_PROTOBUF_C_CLIENT_INCLUDES)
+
+PROTOBUF_INCLUDES=-I$(top_srcdir)
+PROTOBUF_PACKAGE = qpb
+
+lib_LTLIBRARIES = libquagga_pb.la
+libquagga_pb_la_LDFLAGS = -version-info 0:0:0
+
+if HAVE_PROTOBUF
+protobuf_srcs =					\
+	qpb_allocator.c
+
+protobuf_srcs_nodist =				\
+	qpb.pb-c.c
+endif
+
+libquagga_pb_la_SOURCES =			\
+	linear_allocator.h			\
+	qpb.h					\
+	qpb.c					\
+	qpb_allocator.h				\
+	$(protobuf_srcs)
+
+nodist_libquagga_pb_la_SOURCES = $(protobuf_srcs_nodist)
+
+CLEANFILES = $(Q_CLEANFILES)
+BUILT_SOURCES = $(Q_PROTOBUF_SRCS)
+EXTRA_DIST = qpb.proto

+ 1 - 0
qpb/README.txt

@@ -0,0 +1 @@
+Protobuf definitions and code that is applicable to all of quagga.

+ 207 - 0
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);
+    }
+}

+ 29 - 0
qpb/qpb.c

@@ -0,0 +1,29 @@
+/*
+ * qpb.c
+ *
+ * @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.
+ */
+
+/*
+ * Main file for the qpb library.
+ */
+

+ 372 - 0
qpb/qpb.h

@@ -0,0 +1,372 @@
+/*
+ * qpb.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.
+ */
+
+/*
+ * 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, u_char 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, u_char *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;
+  }
+
+  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, u_char family,
+		     struct prefix *prefix)
+{
+
+  switch (family)
+    {
+
+    case AF_INET:
+      memset(prefix, 0, sizeof(struct prefix_ipv4));
+      break;
+
+    case AF_INET6:
+      memset(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_BABEL:
+  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,
+			 u_char 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,
+		      u_char *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

+ 121 - 0
qpb/qpb.proto

@@ -0,0 +1,121 @@
+/*
+ * qpb.proto
+ *
+ * @copyright Copyright (C) 2016 Sproute Networks, Inc.
+ *
+ * @author Avneesh Sachdev <avneesh@sproute.com>
+ *
+ * Permission is granted to use, copy, modify and/or distribute this
+ * software under either one of the licenses below.
+ *
+ * Note that if you use other files from the Quagga tree directly or
+ * indirectly, then the licenses in those files still apply.
+ *
+ * Please retain both licenses below when modifying this code in the
+ * Quagga tree.
+ */
+
+/*
+ * License Option 1: GPL
+ *
+ * This program 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 of the License, or (at your option)
+ * any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+/*
+ * License Option 2: ISC License
+ *
+ * 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.
+ */
+
+/*
+ * Protobuf definitions pertaining to the Quagga 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;
+}

+ 67 - 0
qpb/qpb_allocator.c

@@ -0,0 +1,67 @@
+/*
+ * qpb_allocator.c
+ *
+ * @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.
+ */
+
+#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,
+  8192,
+  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;
+}

+ 113 - 0
qpb/qpb_allocator.h

@@ -0,0 +1,113 @@
+/*
+ * qpb_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 quagga 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_ */