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