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