zebra: optionally use protobuf with FPM
Change zebra so that it can optionally use protobuf serialization when
communicating with a Forwarding Plane Manager component.
* zebra/main.c
Add the --fpm-format/-F command line option. This allows the user
to control the format (protbuf|netlink) that is used to
communicate with the FPM.
* zebra/zebra_fpm.c
- zebra_init_msg_format(),
This new function is invoked on process startup to determine the
FPM format that should be used.
- zfpm_init()
Change to accept any 'FPM message format' specified by the user
(via the new command line flag).
- zebra_encode_route()
Tweak to use the selected FPM format.
* zebra_fpm_protobuf.c
New code to build protobuf messages to be sent to the FPM.
* zebra/Makefile.am
- Include common.am
- Build new file zebra_fpm_protobuf.c when protobuf is available.
- Link with the fpm_pb library.
Signed-off-by: Avneesh Sachdev <avneesh@sproute.com>
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 9cbbf68..22fc6ca 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -139,6 +139,15 @@
} zfpm_state_t;
/*
+ * Message format to be used to communicate with the FPM.
+ */
+typedef enum
+{
+ ZFPM_MSG_FORMAT_NONE,
+ ZFPM_MSG_FORMAT_NETLINK,
+ ZFPM_MSG_FORMAT_PROTOBUF,
+} zfpm_msg_format_e;
+/*
* Globals.
*/
typedef struct zfpm_glob_t_
@@ -149,6 +158,11 @@
*/
int enabled;
+ /*
+ * Message format to be used to communicate with the fpm.
+ */
+ zfpm_msg_format_e message_format;
+
struct thread_master *master;
zfpm_state_t state;
@@ -863,19 +877,40 @@
*/
static inline int
zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf,
- size_t in_buf_len)
+ size_t in_buf_len, fpm_msg_type_e *msg_type)
{
-#ifndef HAVE_NETLINK
- return 0;
-#else
-
+ size_t len;
int cmd;
+ len = 0;
- cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE;
+ *msg_type = FPM_MSG_TYPE_NONE;
- return zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len);
+ switch (zfpm_g->message_format) {
+ case ZFPM_MSG_FORMAT_PROTOBUF:
+#ifdef HAVE_PROTOBUF
+ len = zfpm_protobuf_encode_route (dest, rib, (uint8_t *) in_buf,
+ in_buf_len);
+ *msg_type = FPM_MSG_TYPE_PROTOBUF;
+#endif
+ break;
+
+ case ZFPM_MSG_FORMAT_NETLINK:
+#ifdef HAVE_NETLINK
+ *msg_type = FPM_MSG_TYPE_NETLINK;
+ cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE;
+ len = zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len);
+ assert(fpm_msg_align(len) == len);
+ *msg_type = FPM_MSG_TYPE_NETLINK;
#endif /* HAVE_NETLINK */
+ break;
+
+ default:
+ break;
+ }
+
+ return len;
+
}
/*
@@ -883,7 +918,7 @@
*
* Returns the rib that is to be sent to the FPM for a given dest.
*/
-static struct rib *
+struct rib *
zfpm_route_for_update (rib_dest_t *dest)
{
struct rib *rib;
@@ -919,6 +954,7 @@
fpm_msg_hdr_t *hdr;
struct rib *rib;
int is_add, write_msg;
+ fpm_msg_type_e msg_type;
s = zfpm_g->obuf;
@@ -943,7 +979,6 @@
hdr = (fpm_msg_hdr_t *) buf;
hdr->version = FPM_PROTO_VERSION;
- hdr->msg_type = FPM_MSG_TYPE_NETLINK;
data = fpm_msg_data (hdr);
@@ -963,11 +998,13 @@
}
if (write_msg) {
- data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data);
+ data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data,
+ &msg_type);
assert (data_len);
if (data_len)
{
+ hdr->msg_type = msg_type;
msg_len = fpm_data_len_to_msg_len (data_len);
hdr->msg_len = htons (msg_len);
stream_forward_endp (s, msg_len);
@@ -1569,6 +1606,64 @@
}
+/*
+ * zfpm_init_message_format
+ */
+static inline void
+zfpm_init_message_format (const char *format)
+{
+ int have_netlink, have_protobuf;
+
+ have_netlink = have_protobuf = 0;
+
+#ifdef HAVE_NETLINK
+ have_netlink = 1;
+#endif
+
+#ifdef HAVE_PROTOBUF
+ have_protobuf = 1;
+#endif
+
+ zfpm_g->message_format = ZFPM_MSG_FORMAT_NONE;
+
+ if (!format)
+ {
+ if (have_netlink)
+ {
+ zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK;
+ }
+ else if (have_protobuf)
+ {
+ zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF;
+ }
+ return;
+ }
+
+ if (!strcmp ("netlink", format))
+ {
+ if (!have_netlink)
+ {
+ zlog_err ("FPM netlink message format is not available");
+ return;
+ }
+ zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK;
+ return;
+ }
+
+ if (!strcmp ("protobuf", format))
+ {
+ if (!have_protobuf)
+ {
+ zlog_err ("FPM protobuf message format is not available");
+ return;
+ }
+ zfpm_g->message_format = ZFPM_MSG_FORMAT_PROTOBUF;
+ return;
+ }
+
+ zlog_warn ("Unknown fpm format '%s'", format);
+}
+
/**
* fpm_remote_srv_write
*
@@ -1598,11 +1693,13 @@
*
* @param[in] port port at which FPM is running.
* @param[in] enable TRUE if the zebra FPM module should be enabled
+ * @param[in] format to use to talk to the FPM. Can be 'netink' or 'protobuf'.
*
* Returns TRUE on success.
*/
int
-zfpm_init (struct thread_master *master, int enable, uint16_t port)
+zfpm_init (struct thread_master *master, int enable, uint16_t port,
+ const char *format)
{
static int initialized = 0;
@@ -1618,16 +1715,6 @@
zfpm_g->sock = -1;
zfpm_g->state = ZFPM_STATE_IDLE;
- /*
- * Netlink must currently be available for the Zebra-FPM interface
- * to be enabled.
- */
-#ifndef HAVE_NETLINK
- enable = 0;
-#endif
-
- zfpm_g->enabled = enable;
-
zfpm_stats_init (&zfpm_g->stats);
zfpm_stats_init (&zfpm_g->last_ivl_stats);
zfpm_stats_init (&zfpm_g->cumulative_stats);
@@ -1637,6 +1724,16 @@
install_element (CONFIG_NODE, &fpm_remote_ip_cmd);
install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd);
+ zfpm_init_message_format(format);
+
+ /*
+ * Disable FPM interface if no suitable format is available.
+ */
+ if (zfpm_g->message_format == ZFPM_MSG_FORMAT_NONE)
+ enable = 0;
+
+ zfpm_g->enabled = enable;
+
if (!enable) {
return 1;
}