qpb: Add support for protobuf.

Infrastructure that allows protocol buffers to be used in Quagga. The
changes below comprise of:

  - Build hooks

  - Protobuf definitions for common types.

  - Library routines for working with protobuf, including functions
    that help translate between common quagga types and their protobuf
    equivalents.

Changes:

  * qpb/{Makefile.am,README.txt,qpb.h,.gitignore}

    Add the qpb library, which provides shared code and definitions
    for using protocol buffers in quagga code.

  * qpb/qpb.proto

    Protobuf definitions that can be shared by all of quagga.

  * qpb/linear_allocator.h

    An allocator that allocates memory by walking down towards the end
    of a buffer. This is used to cheaply allocate/deallocate memory on
    the stack for protobuf operations.

  * qpb/qpb_allocator.[ch]

    Thin layer that allows a linear allocator to be used with the
    protobuf-c library.

  * common.am

    This is an automake fragment that is intended to be shared by
    Makefile.am files in the tree. It currently includes definitions
    related to protobuf.

  * configure.ac

    - Add logic to optionally build protobuf code.

      By default, protobuf support is enabled if the protobuf C
      compiler (protoc-c) is available, and the associated header
      files/library can be found.

      The user can choose to override this behavior via the new
      --disable-protobuf/--enable-protobuf flags.

    - Include the quagga protobuf library (qpb) in the build.

  * .gitignore

    Ignore source code generated by protobuf compiler.

  * Makefile.am

    Add 'qpb' to the list of subdirectories.

Signed-off-by: Avneesh Sachdev <avneesh@sproute.com>

Edited: Paul Jakma <paul.jakma@hpe.com>: Change the sense of the
        configure enable option to require explicit specifying, as
        an experimental feature.
This commit is contained in:
Avneesh Sachdev 2016-04-04 10:54:55 -07:00 committed by Donald Sharp
parent 6d24eb2b75
commit dad253b46d
13 changed files with 1047 additions and 3 deletions

3
.gitignore vendored
View file

@ -55,3 +55,6 @@ debian/quagga/
debian/tmp/ debian/tmp/
*.swp *.swp
cscope.* cscope.*
*.pb.h
*.pb-c.h
*.pb-c.c

View file

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

41
common.am Normal file
View file

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

View file

@ -315,6 +315,8 @@ AC_ARG_ENABLE(cumulus,
AS_HELP_STRING([--enable-cumulus], [enable Cumulus Switch Special Extensions])) AS_HELP_STRING([--enable-cumulus], [enable Cumulus Switch Special Extensions]))
AC_ARG_ENABLE(rr-semantics, AC_ARG_ENABLE(rr-semantics,
AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics])) AS_HELP_STRING([--disable-rr-semantics], [disable the v6 Route Replace semantics]))
AC_ARG_ENABLE([protobuf],
AS_HELP_STRING([--enable-protobuf], [Enable experimental protobuf support]))
AC_CHECK_HEADERS(json-c/json.h) AC_CHECK_HEADERS(json-c/json.h)
AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c") AC_CHECK_LIB(json-c, json_object_get, LIBS="$LIBS -ljson-c")
@ -393,6 +395,48 @@ if test "${enable_fpm}" = "yes"; then
AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support) AC_DEFINE(HAVE_FPM,,Forwarding Plane Manager support)
fi fi
#
# Logic for protobuf support.
#
if test "$enable_protobuf" = "yes"; then
have_protobuf=yes
# Check for protoc-c
AC_CHECK_PROG([PROTOC_C], [protoc-c], [protoc-c], [/bin/false])
if test "x$PROTOC_C" = "x/bin/false"; then
have_protobuf=no
else
found_protobuf_c=no
PKG_CHECK_MODULES([PROTOBUF_C], libprotobuf-c >= 0.14,
[found_protobuf_c=yes],
[AC_MSG_RESULT([pkg-config did not find libprotobuf-c])])
if test "x$found_protobuf_c" = "xyes"; then
LDFLAGS="$LDFLAGS $PROTOBUF_C_LIBS"
CFLAGS="$CFLAGS $PROTOBUF_C_CFLAGS"
else
AC_CHECK_HEADER([google/protobuf-c/protobuf-c.h], [],
[have_protobuf=no; AC_MSG_RESULT([Couldn't find google/protobuf-c.h])])
fi
fi
fi
# Fail if the user explicity enabled protobuf support and we couldn't
# find the compiler or libraries.
if test "x$have_protobuf" = "xno" && test "x$enable_protobuf" = "xyes"; then
AC_MSG_ERROR([Protobuf enabled explicitly but can't find libraries/tools])
fi
if test "x$have_protobuf" = "xyes"; then
AC_DEFINE(HAVE_PROTOBUF,, protobuf)
fi
AM_CONDITIONAL([HAVE_PROTOBUF], [test "x$have_protobuf" = "xyes"])
#
# End of logic for protobuf support.
#
if test "${enable_tcp_zebra}" = "yes"; then if test "${enable_tcp_zebra}" = "yes"; then
AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication) AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication)
fi fi
@ -1673,7 +1717,7 @@ AC_CACHE_VAL(ac_cv_htonl_works,
) )
AC_MSG_RESULT($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 ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile
ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
@ -1715,6 +1759,7 @@ group to run as : ${enable_group}
group for vty sockets : ${enable_vty_group} group for vty sockets : ${enable_vty_group}
config file mask : ${enable_configfile_mask} config file mask : ${enable_configfile_mask}
log file mask : ${enable_logfile_mask} log file mask : ${enable_logfile_mask}
zebra protobuf enabled : ${have_protobuf:-no}
The above user and group must have read/write access to the state file The above user and group must have read/write access to the state file
directory and to the config files in the config file directory." directory and to the config files in the config file directory."

15
qpb/.gitignore vendored Normal file
View file

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

30
qpb/Makefile.am Normal file
View file

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

1
qpb/README.txt Normal file
View file

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

207
qpb/linear_allocator.h Normal file
View file

@ -0,0 +1,207 @@
/*
* linear_allocator.h
*
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Quagga; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
/*
* Header file for the linear allocator.
*
* An allocator that allocates memory by walking down towards the end
* of a buffer. No attempt is made to reuse blocks that are freed
* subsequently. The assumption is that the buffer is big enough to
* cover allocations for a given purpose.
*/
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h>
/*
* Alignment for block allocated by the allocator. Must be a power of 2.
*/
#define LINEAR_ALLOCATOR_ALIGNMENT 8
#define LINEAR_ALLOCATOR_ALIGN(value) \
(((value) + LINEAR_ALLOCATOR_ALIGNMENT - 1) & ~(LINEAR_ALLOCATOR_ALIGNMENT - 1));
/*
* linear_allocator_align_ptr
*/
static inline char *
linear_allocator_align_ptr (char *ptr)
{
return (char *) LINEAR_ALLOCATOR_ALIGN ((intptr_t) ptr);
}
typedef struct linear_allocator_t_
{
char *buf;
/*
* Current location in the buffer.
*/
char *cur;
/*
* End of buffer.
*/
char *end;
/*
* Version number of the allocator, this is bumped up when the allocator
* is reset and helps identifies bad frees.
*/
uint32_t version;
/*
* The number of blocks that are currently allocated.
*/
int num_allocated;
} linear_allocator_t;
/*
* linear_allocator_block_t
*
* Header structure at the begining of each block.
*/
typedef struct linear_allocator_block_t_
{
uint32_t flags;
/*
* The version of the allocator when this block was allocated.
*/
uint32_t version;
char data[0];
} linear_allocator_block_t;
#define LINEAR_ALLOCATOR_BLOCK_IN_USE 0x01
#define LINEAR_ALLOCATOR_HDR_SIZE (sizeof(linear_allocator_block_t))
/*
* linear_allocator_block_size
*
* The total amount of space a block will take in the buffer,
* including the size of the header.
*/
static inline size_t
linear_allocator_block_size (size_t user_size)
{
return LINEAR_ALLOCATOR_ALIGN (LINEAR_ALLOCATOR_HDR_SIZE + user_size);
}
/*
* linear_allocator_ptr_to_block
*/
static inline linear_allocator_block_t *
linear_allocator_ptr_to_block (void *ptr)
{
void *block_ptr;
block_ptr = ((char *) ptr) - offsetof (linear_allocator_block_t, data);
return block_ptr;
}
/*
* linear_allocator_init
*/
static inline void
linear_allocator_init (linear_allocator_t * allocator, char *buf,
size_t buf_len)
{
memset (allocator, 0, sizeof (*allocator));
assert (linear_allocator_align_ptr (buf) == buf);
allocator->buf = buf;
allocator->cur = buf;
allocator->end = buf + buf_len;
}
/*
* linear_allocator_reset
*
* Prepare an allocator for reuse.
*
* *** NOTE ** This implicitly frees all the blocks in the allocator.
*/
static inline void
linear_allocator_reset (linear_allocator_t *allocator)
{
allocator->num_allocated = 0;
allocator->version++;
allocator->cur = allocator->buf;
}
/*
* linear_allocator_alloc
*/
static inline void *
linear_allocator_alloc (linear_allocator_t *allocator, size_t user_size)
{
size_t block_size;
linear_allocator_block_t *block;
block_size = linear_allocator_block_size (user_size);
if (allocator->cur + block_size > allocator->end)
{
return NULL;
}
block = (linear_allocator_block_t *) allocator->cur;
allocator->cur += block_size;
block->flags = LINEAR_ALLOCATOR_BLOCK_IN_USE;
block->version = allocator->version;
allocator->num_allocated++;
return block->data;
}
/*
* linear_allocator_free
*/
static inline void
linear_allocator_free (linear_allocator_t *allocator, void *ptr)
{
linear_allocator_block_t *block;
if (((char *) ptr) < allocator->buf || ((char *) ptr) >= allocator->end)
{
assert (0);
return;
}
block = linear_allocator_ptr_to_block (ptr);
if (block->version != allocator->version)
{
assert (0);
return;
}
block->flags = block->flags & ~LINEAR_ALLOCATOR_BLOCK_IN_USE;
if (--allocator->num_allocated < 0)
{
assert (0);
}
}

29
qpb/qpb.c Normal file
View file

@ -0,0 +1,29 @@
/*
* qpb.c
*
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Quagga; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
/*
* Main file for the qpb library.
*/

372
qpb/qpb.h Normal file
View file

@ -0,0 +1,372 @@
/*
* qpb.h
*
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Quagga; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
/*
* Main public header file for the quagga protobuf library.
*/
#ifndef _QPB_H
#define _QPB_H
#include "prefix.h"
#include "qpb/qpb.pb-c.h"
#include "qpb/qpb_allocator.h"
/*
* qpb__address_family__set
*/
#define qpb_address_family_set qpb__address_family__set
static inline int
qpb__address_family__set (Qpb__AddressFamily *pb_family, u_char family)
{
switch (family) {
case AF_INET:
*pb_family = QPB__ADDRESS_FAMILY__IPV4;
return 1;
case AF_INET6:
*pb_family = QPB__ADDRESS_FAMILY__IPV6;
return 1;
default:
*pb_family = QPB__ADDRESS_FAMILY__UNKNOWN_AF;
}
return 0;
}
/*
* qpb__address_family__get
*/
#define qpb_address_family_get qpb__address_family__get
static inline int
qpb__address_family__get (Qpb__AddressFamily pb_family, u_char *family)
{
switch (pb_family) {
case QPB__ADDRESS_FAMILY__IPV4:
*family = AF_INET;
return 1;
case QPB__ADDRESS_FAMILY__IPV6:
*family = AF_INET6;
return 1;
case QPB__ADDRESS_FAMILY__UNKNOWN_AF:
return 0;
}
return 0;
}
/*
* qpb__l3_prefix__create
*/
#define qpb_l3_prefix_create qpb__l3_prefix__create
static inline Qpb__L3Prefix *
qpb__l3_prefix__create (qpb_allocator_t *allocator, struct prefix *p)
{
Qpb__L3Prefix *prefix;
prefix = QPB_ALLOC(allocator, typeof(*prefix));
if (!prefix) {
return NULL;
}
qpb__l3_prefix__init(prefix);
prefix->length = p->prefixlen;
prefix->bytes.len = (p->prefixlen + 7)/8;
prefix->bytes.data = qpb_alloc(allocator, prefix->bytes.len);
if (!prefix->bytes.data) {
return NULL;
}
memcpy(prefix->bytes.data, &p->u.prefix, prefix->bytes.len);
return prefix;
}
/*
* qpb__l3_prefix__get
*/
#define qpb_l3_prefix_get qpb__l3_prefix__get
static inline int
qpb__l3_prefix__get (const Qpb__L3Prefix *pb_prefix, u_char family,
struct prefix *prefix)
{
switch (family)
{
case AF_INET:
memset(prefix, 0, sizeof(struct prefix_ipv4));
break;
case AF_INET6:
memset(prefix, 0, sizeof(struct prefix_ipv6));
break;
default:
memset(prefix, 0, sizeof(*prefix));
}
prefix->prefixlen = pb_prefix->length;
prefix->family = family;
memcpy(&prefix->u.prefix, pb_prefix->bytes.data, pb_prefix->bytes.len);
return 1;
}
/*
* qpb__protocol__set
*
* Translate a quagga route type to a protobuf protocol.
*/
#define qpb_protocol_set qpb__protocol__set
static inline int
qpb__protocol__set (Qpb__Protocol *pb_proto, int route_type)
{
switch (route_type) {
case ZEBRA_ROUTE_KERNEL:
*pb_proto = QPB__PROTOCOL__KERNEL;
break;
case ZEBRA_ROUTE_CONNECT:
*pb_proto = QPB__PROTOCOL__CONNECTED;
break;
case ZEBRA_ROUTE_STATIC:
*pb_proto = QPB__PROTOCOL__STATIC;
break;
case ZEBRA_ROUTE_RIP:
*pb_proto = QPB__PROTOCOL__RIP;
break;
case ZEBRA_ROUTE_RIPNG:
*pb_proto = QPB__PROTOCOL__RIPNG;
break;
case ZEBRA_ROUTE_OSPF:
case ZEBRA_ROUTE_OSPF6:
*pb_proto = QPB__PROTOCOL__OSPF;
break;
case ZEBRA_ROUTE_ISIS:
*pb_proto = QPB__PROTOCOL__ISIS;
break;
case ZEBRA_ROUTE_BGP:
*pb_proto = QPB__PROTOCOL__BGP;
break;
case ZEBRA_ROUTE_HSLS:
case ZEBRA_ROUTE_OLSR:
case ZEBRA_ROUTE_BABEL:
case ZEBRA_ROUTE_MAX:
case ZEBRA_ROUTE_SYSTEM:
default:
*pb_proto = QPB__PROTOCOL__OTHER;
}
return 1;
}
/*
* qpb__ipv4_address__create
*/
static inline Qpb__Ipv4Address *
qpb__ipv4_address__create (qpb_allocator_t *allocator,
struct in_addr *addr)
{
Qpb__Ipv4Address *v4;
v4 = QPB_ALLOC(allocator, typeof(*v4));
if (!v4) {
return NULL;
}
qpb__ipv4_address__init(v4);
v4->value = ntohl(addr->s_addr);
return v4;
}
/*
* qpb__ipv4_address__get
*/
static inline int
qpb__ipv4_address__get (const Qpb__Ipv4Address *v4, struct in_addr *addr)
{
addr->s_addr = htonl(v4->value);
return 1;
}
/*
* qpb__ipv6_address__create
*/
static inline Qpb__Ipv6Address *
qpb__ipv6_address__create (qpb_allocator_t *allocator, struct in6_addr *addr)
{
Qpb__Ipv6Address *v6;
v6 = QPB_ALLOC(allocator, typeof(*v6));
if (!v6)
return NULL;
qpb__ipv6_address__init(v6);
v6->bytes.len = 16;
v6->bytes.data = qpb_alloc(allocator, 16);
if (!v6->bytes.data)
return NULL;
memcpy(v6->bytes.data, addr->s6_addr, v6->bytes.len);
return v6;
}
/*
* qpb__ipv6_address__get
*
* Read out information from a protobuf ipv6 address structure.
*/
static inline int
qpb__ipv6_address__get (const Qpb__Ipv6Address *v6, struct in6_addr *addr)
{
if (v6->bytes.len != 16)
return 0;
memcpy(addr->s6_addr, v6->bytes.data, v6->bytes.len);
return 1;
}
/*
* qpb__l3_address__create
*/
#define qpb_l3_address_create qpb__l3_address__create
static inline Qpb__L3Address *
qpb__l3_address__create (qpb_allocator_t *allocator, union g_addr *addr,
u_char family)
{
Qpb__L3Address *l3_addr;
l3_addr = QPB_ALLOC(allocator, typeof(*l3_addr));
if (!l3_addr)
return NULL;
qpb__l3_address__init(l3_addr);
switch (family) {
case AF_INET:
l3_addr->v4 = qpb__ipv4_address__create (allocator, &addr->ipv4);
if (!l3_addr->v4)
return NULL;
break;
case AF_INET6:
l3_addr->v6 = qpb__ipv6_address__create (allocator, &addr->ipv6);
if (!l3_addr->v6)
return NULL;
break;
}
return l3_addr;
}
/*
* qpb__l3_address__get
*
* Read out a gateway address from a protobuf l3 address.
*/
#define qpb_l3_address_get qpb__l3_address__get
static inline int
qpb__l3_address__get (const Qpb__L3Address *l3_addr,
u_char *family, union g_addr *addr)
{
if (l3_addr->v4)
{
qpb__ipv4_address__get (l3_addr->v4, &addr->ipv4);
*family = AF_INET;
return 1;
}
if (l3_addr->v6)
{
qpb__ipv6_address__get(l3_addr->v6, &addr->ipv6);
*family = AF_INET6;
return 1;
}
return 0;
}
/*
* qpb__if_identifier__create
*/
#define qpb_if_identifier_create qpb__if_identifier__create
static inline Qpb__IfIdentifier *
qpb__if_identifier__create (qpb_allocator_t *allocator, uint if_index)
{
Qpb__IfIdentifier *if_id;
if_id = QPB_ALLOC(allocator, typeof(*if_id));
if (!if_id) {
return NULL;
}
qpb__if_identifier__init(if_id);
if_id->has_index = 1;
if_id->index = if_index;
return if_id;
}
/*
* qpb__if_identifier__get
*
* Get interface name and/or if_index from an if identifier.
*/
#define qpb_if_identifier_get qpb__if_identifier__get
static inline int
qpb__if_identifier__get (Qpb__IfIdentifier *if_id, uint *if_index,
char **name)
{
char *str;
uint ix;
if (!if_index)
if_index = &ix;
if (!name)
name = &str;
if (if_id->has_index)
*if_index = if_id->index;
else
*if_index = 0;
*name = if_id->name;
return 1;
}
#endif

121
qpb/qpb.proto Normal file
View file

@ -0,0 +1,121 @@
/*
* qpb.proto
*
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
*
* Permission is granted to use, copy, modify and/or distribute this
* software under either one of the licenses below.
*
* Note that if you use other files from the Quagga tree directly or
* indirectly, then the licenses in those files still apply.
*
* Please retain both licenses below when modifying this code in the
* Quagga tree.
*/
/*
* License Option 1: GPL
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* License Option 2: ISC License
*
* Permission to use, copy, modify, and/or distribute this software
* for any purpose with or without fee is hereby granted, provided
* that the above copyright notice and this permission notice appear
* in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Protobuf definitions pertaining to the Quagga Protobuf component.
*/
package qpb;
enum AddressFamily {
UNKNOWN_AF = 0;
IPV4 = 1; // IP version 4
IPV6 = 2; // IP version 6
};
enum SubAddressFamily {
UNKNOWN_SAF = 0;
UNICAST = 1;
MULTICAST = 2;
};
//
// An IP version 4 address, such as 10.1.1.1.
//
message Ipv4Address {
required fixed32 value = 1 ;
};
message Ipv6Address {
// 16 bytes.
required bytes bytes = 1;
};
//
// An IP version 4 or IP version 6 address.
//
message L3Address {
optional Ipv4Address v4 = 1;
optional Ipv6Address v6 = 2;
};
//
// An IP prefix, such as 10.1/16.
// We use the message below to represent both IPv4 and IPv6 prefixes.
message L3Prefix {
required uint32 length = 1;
required bytes bytes = 2;
};
//
// Something that identifies an interface on a machine. It can either
// be a name (for instance, 'eth0') or a number currently.
//
message IfIdentifier {
optional uint32 index = 1;
optional string name = 2;
};
enum Protocol {
UNKNOWN_PROTO = 0;
LOCAL = 1;
CONNECTED = 2;
KERNEL = 3;
STATIC = 4;
RIP = 5;
RIPNG = 6;
OSPF = 7;
ISIS = 8;
BGP = 9;
OTHER = 10;
}

67
qpb/qpb_allocator.c Normal file
View file

@ -0,0 +1,67 @@
/*
* qpb_allocator.c
*
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Quagga; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include "linear_allocator.h"
#include "qpb_allocator.h"
/*
* _qpb_alloc
*/
static void *
_qpb_alloc (void *allocator_data, size_t size)
{
return linear_allocator_alloc (allocator_data, size);
}
/*
* _qpb_free
*/
static void
_qpb_free (void *allocator_data, void *ptr)
{
linear_allocator_free (allocator_data, ptr);
}
static ProtobufCAllocator allocator_template = {
_qpb_alloc,
_qpb_free,
NULL,
8192,
NULL
};
/*
* qpb_allocator_init_linear
*
* Initialize qpb_allocator_t with the given linear allocator.
*/
void
qpb_allocator_init_linear (qpb_allocator_t *allocator,
linear_allocator_t *linear_allocator)
{
*allocator = allocator_template;
allocator->allocator_data = linear_allocator;
}

113
qpb/qpb_allocator.h Normal file
View file

@ -0,0 +1,113 @@
/*
* qpb_allocator.h
*
* @copyright Copyright (C) 2016 Sproute Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.com>
*
* This file is part of Quagga.
*
* Quagga is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Quagga is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Quagga; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
/*
* Header file for quagga protobuf memory management code.
*/
#ifndef _QPB_ALLOCATOR_H_
#define _QPB_ALLOCATOR_H_
#include <google/protobuf-c/protobuf-c.h>
struct linear_allocator_t_;
/*
* Alias for ProtobufCAllocator that is easier on the fingers.
*/
typedef ProtobufCAllocator qpb_allocator_t;
/*
* qpb_alloc
*/
static inline void *
qpb_alloc (qpb_allocator_t *allocator, size_t size)
{
return allocator->alloc (allocator->allocator_data, size);
}
/*
* qpb_alloc_ptr_array
*
* Allocate space for the specified number of pointers.
*/
static inline void *
qpb_alloc_ptr_array (qpb_allocator_t *allocator, size_t num_ptrs)
{
return qpb_alloc (allocator, num_ptrs * sizeof (void *));
}
/*
* qpb_free
*/
static inline void
qpb_free (qpb_allocator_t *allocator, void *ptr)
{
allocator->free (allocator->allocator_data, ptr);
}
/*
* QPB_ALLOC
*
* Convenience macro to reduce the probability of allocating memory of
* incorrect size. It returns enough memory to store the given type,
* and evaluates to an appropriately typed pointer.
*/
#define QPB_ALLOC(allocator, type) \
(type *) qpb_alloc(allocator, sizeof(type))
/*
* Externs.
*/
extern void qpb_allocator_init_linear (qpb_allocator_t *,
struct linear_allocator_t_ *);
/*
* The following macros are for the common case where a qpb allocator
* is being used alongside a linear allocator that allocates memory
* off of the stack.
*/
#define QPB_DECLARE_STACK_ALLOCATOR(allocator, size) \
qpb_allocator_t allocator; \
linear_allocator_t lin_ ## allocator; \
char lin_ ## allocator ## _buf[size]
#define QPB_INIT_STACK_ALLOCATOR(allocator) \
do \
{ \
linear_allocator_init(&(lin_ ## allocator), \
lin_ ## allocator ## _buf, \
sizeof(lin_ ## allocator ## _buf)); \
qpb_allocator_init_linear(&allocator, &(lin_ ## allocator)); \
} while (0)
#define QPB_RESET_STACK_ALLOCATOR(allocator) \
do \
{ \
linear_allocator_reset (&(lin_ ## allocator)); \
} while (0)
#endif /* _QPB_ALLOCATOR_H_ */