On Mon, Mar 14, 2016 at 6:04 AM, Donald Sharp <[email protected]> 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? > Protobuf (or similar) is better than netlink because code for encode/decode is generated automatically. This reduces bugs in the code, allows third-party programs to be integrated quickly and makes it easy to add fields. In addition, the format is not tied to an OS and can be evolved independently. Some more thoughts inline. > > > On Fri, Mar 11, 2016 at 3:21 PM, Avneesh Sachdev <[email protected]> > 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 <[email protected]> >> --- >> .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? > The new file common.am uses gmake constructs and is included from multiple makefiles, causing many warnings to be spit out. So, it would be nice for this to go in before or with the protobuf changes. I can break it out into a separate patch if you like. 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 <[email protected]> >> + * >> + * This file is part of GNU Zebra. >> > > > 1,$s/GNU Zebra/Quagga/ > please. For all new files. > Sure, will do. > > > >> + * >> + * 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 <[email protected]> >> + * >> + * 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 <[email protected]> >> + * >> + * 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? > Sounds good. FWIW, these should be easy to add once the base infrastructure is in place. > 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? > Sure, happy to contribute a blurb. Thanks! Avneesh > > 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 <[email protected]> >> + * >> + * 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 <[email protected]> >> + * >> + * 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 >> [email protected] >> https://lists.quagga.net/mailman/listinfo/quagga-dev >> > >
_______________________________________________ Quagga-dev mailing list [email protected] https://lists.quagga.net/mailman/listinfo/quagga-dev
