My API presentation tomorrow includes a section on why we choose Cap'n
Proto and why it is better than Protobuf ;)

The biggest argument is:
> >   - Library routines for working with protobuf, including functions
> >     that help translate between common quagga types and their protobuf
> >     equivalents.
I came up with a way to avoid these as much as possible.

That said, I don't disagree with this patchset.  If nothing else, it
might be nice to modularize things so that it is easier to change
interfaces.

Cheers,


-David

On Mon, Mar 14, 2016 at 09:04:33AM -0400, Donald Sharp wrote:
> Can you give us some background on why proto-buf was choosen as a
> communication methodology and why it's superior from a netlink perspective?
> 
> Some more thoughts inline.
> 
> 
> On Fri, Mar 11, 2016 at 3:21 PM, Avneesh Sachdev <avne...@sproute.com>
> wrote:
> 
> > 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 <avne...@sproute.com>
> > ---
> >  .gitignore             |   3 +
> >  Makefile.am            |   2 +-
> >  common.am              |  39 ++++++
> >  configure.ac           |  52 ++++++-
> >  qpb/.gitignore         |  15 ++
> >  qpb/Makefile.am        |  20 +++
> >  qpb/README.txt         |   1 +
> >  qpb/linear_allocator.h | 207 +++++++++++++++++++++++++++
> >  qpb/qpb.h              | 372
> > +++++++++++++++++++++++++++++++++++++++++++++++++
> >  qpb/qpb.proto          | 121 ++++++++++++++++
> >  qpb/qpb_allocator.c    |  67 +++++++++
> >  qpb/qpb_allocator.h    | 113 +++++++++++++++
> >  12 files changed, 1009 insertions(+), 3 deletions(-)
> >  create mode 100644 common.am
> >  create mode 100644 qpb/.gitignore
> >  create mode 100644 qpb/Makefile.am
> >  create mode 100644 qpb/README.txt
> >  create mode 100644 qpb/linear_allocator.h
> >  create mode 100644 qpb/qpb.h
> >  create mode 100644 qpb/qpb.proto
> >  create mode 100644 qpb/qpb_allocator.c
> >  create mode 100644 qpb/qpb_allocator.h
> >
> > diff --git a/.gitignore b/.gitignore
> > index e8de252..a281555 100644
> > --- a/.gitignore
> > +++ b/.gitignore
> > @@ -38,3 +38,6 @@ build
> >  m4/*.m4
> >  !m4/ax_sys_weak_alias.m4
> >  cscope.*
> > +*.pb.h
> > +*.pb-c.h
> > +*.pb-c.c
> > diff --git a/Makefile.am b/Makefile.am
> > index d2efb20..ece8a59 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -1,6 +1,6 @@
> >  ## 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
> >
> > diff --git a/common.am b/common.am
> > new file mode 100644
> > index 0000000..dc79479
> > --- /dev/null
> > +++ b/common.am
> > @@ -0,0 +1,39 @@
> > +#
> > +# 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)
> > +
> > +endif  # HAVE_PROTOBUF
> > +
> > +Q_CLEANFILES = $(Q_PROTOBUF_SRCS)
> > +
> > +Q_BUILT_SRCS = $(Q_PROTOBUF_SRCS)
> > diff --git a/configure.ac b/configure.ac
> > index 3003e62..51be70a 100755
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -20,7 +20,10 @@ AC_CANONICAL_BUILD()
> >  AC_CANONICAL_HOST()
> >  AC_CANONICAL_TARGET()
> >
> > -AM_INIT_AUTOMAKE(1.6)
> > +# Disable portability warnings -- our automake code (in particular
> > +# common.am) uses some constructs specific to gmake.
> > +AM_INIT_AUTOMAKE([1.6 -Wno-portability])
> > +
> >
> 
> This hunk sure seems like it should be it's own separate patch.  It seems
> like a reasonable fix but I don't think it needs to be part of the generic
> add of protobuff to the system?
> 
> 
> 
> >  AM_SILENT_RULES([yes])
> >  AC_CONFIG_HEADERS(config.h)
> >
> > @@ -302,6 +305,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([--disable-protobuf], [Ignore presence of protobuf and
> > disable it]))
> >
> >  if test x"${enable_gcc_rdynamic}" != x"no" ; then
> >    if test x"${enable_gcc_rdynamic}" = x"yes" -o x"$COMPILER" = x"GCC";
> > then
> > @@ -321,6 +326,49 @@ if test "${enable_fpm}" = "yes"; then
> >     AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support)
> >  fi
> >
> > +#
> > +# Logic for protobuf support.
> > +#
> > +have_protobuf=no
> > +if test "x$enable_protobuf" != "xno"; 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
> > @@ -1547,7 +1595,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
> > diff --git a/qpb/.gitignore b/qpb/.gitignore
> > new file mode 100644
> > index 0000000..b133c52
> > --- /dev/null
> > +++ b/qpb/.gitignore
> > @@ -0,0 +1,15 @@
> > +Makefile
> > +Makefile.in
> > +*.o
> > +tags
> > +TAGS
> > +.deps
> > +.nfs*
> > +*.lo
> > +*.la
> > +*.a
> > +*.libs
> > +.arch-inventory
> > +.arch-ids
> > +*~
> > +*.loT
> > diff --git a/qpb/Makefile.am b/qpb/Makefile.am
> > new file mode 100644
> > index 0000000..549f027
> > --- /dev/null
> > +++ b/qpb/Makefile.am
> > @@ -0,0 +1,20 @@
> > +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.pb-c.c                      \
> > +       qpb_allocator.c
> > +endif
> > +
> > +libquagga_pb_la_SOURCES = $(protobuf_srcs)
> > +
> > +CLEANFILES = $(Q_CLEANFILES)
> > +BUILT_SOURCES = $(Q_PROTOBUF_SRCS)
> > diff --git a/qpb/README.txt b/qpb/README.txt
> > new file mode 100644
> > index 0000000..99ccd05
> > --- /dev/null
> > +++ b/qpb/README.txt
> > @@ -0,0 +1 @@
> > +Protobuf definitions and code that is applicable to all of quagga.
> > diff --git a/qpb/linear_allocator.h b/qpb/linear_allocator.h
> > new file mode 100644
> > index 0000000..f5cc49f
> > --- /dev/null
> > +++ b/qpb/linear_allocator.h
> > @@ -0,0 +1,207 @@
> > +/*
> > + * linear_allocator.h
> > + *
> > + * @copyright Copyright (C) 2016 Sproute Networks, Inc.
> > + *
> > + * @author Avneesh Sachdev <avne...@sproute.com>
> > + *
> > + * This file is part of GNU Zebra.
> >
> 
> 
> 1,$s/GNU Zebra/Quagga/
> please.  For all new files.
> 
> 
> 
> > + *
> > + * GNU Zebra 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.
> > + *
> > + * GNU Zebra 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 GNU Zebra; 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);
> > +    }
> > +}
> > diff --git a/qpb/qpb.h b/qpb/qpb.h
> > new file mode 100644
> > index 0000000..2ff2804
> > --- /dev/null
> > +++ b/qpb/qpb.h
> > @@ -0,0 +1,372 @@
> > +/*
> > + * qpb.h
> > + *
> > + * @copyright Copyright (C) 2016 Sproute Networks, Inc.
> > + *
> > + * @author Avneesh Sachdev <avne...@sproute.com>
> > + *
> > + * This file is part of GNU Zebra.
> > + *
> > + * GNU Zebra 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.
> > + *
> > + * GNU Zebra 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 GNU Zebra; 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
> > diff --git a/qpb/qpb.proto b/qpb/qpb.proto
> > new file mode 100644
> > index 0000000..7ee409d
> > --- /dev/null
> > +++ b/qpb/qpb.proto
> > @@ -0,0 +1,121 @@
> > +/*
> > + * qpb.proto
> > + *
> > + * @copyright Copyright (C) 2016 Sproute Networks, Inc.
> > + *
> > + * @author Avneesh Sachdev <avne...@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;
> > +};
> >
> 
> What's the plan for VPNv4 and 6, as well as MPLS?  These are coming in
> *soonish* so let's start thinking about handling them now?
> 
> The reasoning about why I am asking about thought process for protobuf -vs-
> netlink.  I want it documented.  Can you provide some documentation for the
> doc/ directory to talk about design choices and how this is all planed to
> go together?
> 
> donald
> 
> 
> > +
> > +//
> > +// 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;
> > +}
> > \ No newline at end of file
> > diff --git a/qpb/qpb_allocator.c b/qpb/qpb_allocator.c
> > new file mode 100644
> > index 0000000..2d9070d
> > --- /dev/null
> > +++ b/qpb/qpb_allocator.c
> > @@ -0,0 +1,67 @@
> > +/*
> > + * qpb_allocator.c
> > + *
> > + * @copyright Copyright (C) 2016 Sproute Networks, Inc.
> > + *
> > + * @author Avneesh Sachdev <avne...@sproute.com>
> > + *
> > + * This file is part of GNU Zebra.
> > + *
> > + * GNU Zebra 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.
> > + *
> > + * GNU Zebra 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 GNU Zebra; 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;
> > +}
> > diff --git a/qpb/qpb_allocator.h b/qpb/qpb_allocator.h
> > new file mode 100644
> > index 0000000..c987f23
> > --- /dev/null
> > +++ b/qpb/qpb_allocator.h
> > @@ -0,0 +1,113 @@
> > +/*
> > + * qpb_allocator.h
> > + *
> > + * @copyright Copyright (C) 2016 Sproute Networks, Inc.
> > + *
> > + * @author Avneesh Sachdev <avne...@sproute.com>
> > + *
> > + * This file is part of GNU Zebra.
> > + *
> > + * GNU Zebra 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.
> > + *
> > + * GNU Zebra 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 GNU Zebra; 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_ */
> > --
> > 1.9.1
> >
> >
> > _______________________________________________
> > Quagga-dev mailing list
> > Quagga-dev@lists.quagga.net
> > https://lists.quagga.net/mailman/listinfo/quagga-dev
> >

> _______________________________________________
> Quagga-dev mailing list
> Quagga-dev@lists.quagga.net
> https://lists.quagga.net/mailman/listinfo/quagga-dev



_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to