Added keepalives to the FPM protocol.
This bumps the FPM protocol version to indicate that we are using
ONOS-specific protocol extensions.
The FPM client (i.e. zebra) will send keepalive messages periodically
on the FPM TCP connections. The keepalive message is designated by a
new message type. Keepalive messages have no body.
diff --git a/fpm/fpm.h b/fpm/fpm.h
index 9a1dbf2..9632810 100644
--- a/fpm/fpm.h
+++ b/fpm/fpm.h
@@ -129,9 +129,10 @@
} fpm_msg_hdr_t;
/*
- * The current version of the FPM protocol is 1.
+ * Bump protocol version to 32 to indicate this includes the
+ * ONOS protocol extensions.
*/
-#define FPM_PROTO_VERSION 1
+#define FPM_PROTO_VERSION 32
typedef enum fpm_msg_type_e_ {
FPM_MSG_TYPE_NONE = 0,
@@ -141,6 +142,14 @@
* message.
*/
FPM_MSG_TYPE_NETLINK = 1,
+ FPM_MSG_TYPE_PROTOBUF = 2,
+
+ /*
+ * Periodic keepalive message. This message is sent periodically by
+ * the FPM client to give the server an indication that the client
+ * is still alive. The message has no content.
+ */
+ FPM_MSG_TYPE_KEEPALIVE = 32,
} fpm_msg_type_e;
/*
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index fa2bc3a..dfc31e7 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -60,6 +60,13 @@
#define ZFPM_STATS_IVL_SECS 10
/*
+ * Default keepalive interval.
+ */
+#define ZFPM_KEEPALIVE_IVL_SECS 2
+
+#define FPM_STR "Forwarding Plane Manager configuration\n"
+
+/*
* Structure that holds state for iterating over all route_node
* structures that are candidates for being communicated to the FPM.
*/
@@ -94,6 +101,8 @@
unsigned long dests_del_after_update;
+ unsigned long keepalive_cb_calls;
+
unsigned long t_conn_down_starts;
unsigned long t_conn_down_dests_processed;
unsigned long t_conn_down_yields;
@@ -198,6 +207,13 @@
*/
struct thread *t_conn_up;
+ /*
+ * Thread to send keepalive messages periodically.
+ */
+ struct thread *t_keepalive;
+
+ uint32_t keepalive_ivl;
+
struct {
zfpm_rnodes_iter_t iter;
} t_conn_up_state;
@@ -239,6 +255,8 @@
static int zfpm_read_cb (struct thread *thread);
static int zfpm_write_cb (struct thread *thread);
+static int zfpm_keepalive_cb (struct thread *thread);
+static int zfpm_create_keepalive (struct thread *thread);
static void zfpm_set_state (zfpm_state_t state, const char *reason);
static void zfpm_start_connect_timer (const char *reason);
@@ -516,6 +534,24 @@
THREAD_WRITE_OFF (zfpm_g->t_write);
}
+static void
+zfpm_keepalive_on ()
+{
+ zfpm_g->t_keepalive = NULL;
+ assert (!zfpm_g->t_keepalive);
+
+ THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_keepalive, zfpm_keepalive_cb,
+ 0, zfpm_g->keepalive_ivl);
+}
+
+static void
+zfpm_keepalive_off ()
+{
+ if (zfpm_g->t_keepalive) {
+ THREAD_TIMER_OFF(zfpm_g->t_keepalive);
+ }
+}
+
/*
* zfpm_conn_up_thread_cb
*
@@ -573,6 +609,57 @@
}
/*
+ * zfpm_keepalive_cb
+ *
+ * Called when the keepalive timer expires.
+ */
+static int
+zfpm_keepalive_cb (struct thread *thread)
+{
+ zfpm_g->stats.keepalive_cb_calls++;
+
+ zfpm_create_keepalive(thread);
+ zfpm_write_on();
+
+ zfpm_keepalive_on();
+
+ return 0;
+}
+
+/*
+ * zfpm_create_keepalive.
+ *
+ * Creates a keepalive message and writes it to the output buffer
+ * ready for sending.
+ */
+static int
+zfpm_create_keepalive (struct thread *thread)
+{
+ fpm_msg_hdr_t *hdr;
+ struct stream *s;
+ unsigned char *buf;
+ uint msg_len = FPM_MSG_HDR_LEN;
+
+ s = zfpm_g->obuf;
+
+ if (STREAM_WRITEABLE (s) < msg_len) {
+ return 1;
+ }
+
+ buf = STREAM_DATA (s) + stream_get_endp (s);
+
+ hdr = (fpm_msg_hdr_t *) buf;
+
+ hdr->version = FPM_PROTO_VERSION;
+ hdr->msg_type = FPM_MSG_TYPE_KEEPALIVE;
+ hdr->msg_len = htons(msg_len);
+
+ stream_forward_endp (s, msg_len);
+
+ return 0;
+}
+
+/*
* zfpm_connection_up
*
* Called when the connection to the FPM comes up.
@@ -596,6 +683,9 @@
zfpm_g->t_conn_up = thread_add_background (zfpm_g->master,
zfpm_conn_up_thread_cb, 0, 0);
zfpm_g->stats.t_conn_up_starts++;
+
+ zfpm_debug ("Starting keepalive thread");
+ zfpm_keepalive_on();
}
/*
@@ -692,6 +782,8 @@
zfpm_g->stats.t_conn_down_finishes++;
zfpm_rnodes_iter_cleanup (iter);
+ zfpm_keepalive_off ();
+
/*
* Start the process of connecting to the FPM again.
*/
@@ -1449,6 +1541,7 @@
ZFPM_SHOW_STAT (non_fpm_table_triggers);
ZFPM_SHOW_STAT (redundant_triggers);
ZFPM_SHOW_STAT (dests_del_after_update);
+ ZFPM_SHOW_STAT (keepalive_cb_calls);
ZFPM_SHOW_STAT (t_conn_down_starts);
ZFPM_SHOW_STAT (t_conn_down_dests_processed);
ZFPM_SHOW_STAT (t_conn_down_yields);
@@ -1528,9 +1621,12 @@
DEFUN ( fpm_remote_ip,
fpm_remote_ip_cmd,
"fpm connection ip A.B.C.D port <1-65535>",
- "fpm connection remote ip and port\n"
- "Remote fpm server ip A.B.C.D\n"
- "Enter ip ")
+ FPM_STR
+ "Connection configuration\n"
+ "Remote FPM server IP\n"
+ "IP address A.B.C.D\n"
+ "Remote FPM server port number\n"
+ "Port number")
{
in_addr_t fpm_server;
@@ -1561,10 +1657,13 @@
DEFUN ( no_fpm_remote_ip,
no_fpm_remote_ip_cmd,
"no fpm connection ip A.B.C.D port <1-65535>",
- "fpm connection remote ip and port\n"
- "Connection\n"
- "Remote fpm server ip A.B.C.D\n"
- "Enter ip ")
+ NO_STR
+ FPM_STR
+ "Connection configuration\n"
+ "Remote FPM server IP\n"
+ "IP address A.B.C.D\n"
+ "Remote FPM server port number\n"
+ "Port number")
{
if (zfpm_g->fpm_server != inet_addr (argv[0]) ||
zfpm_g->fpm_port != atoi (argv[1]))
@@ -1579,16 +1678,53 @@
return CMD_SUCCESS;
}
+DEFUN ( fpm_keepalive_timer,
+ fpm_keepalive_timer_cmd,
+ "fpm keepalive timer <1-65535>",
+ FPM_STR
+ "Keepalive configuration\n"
+ "Keepalive timer\n"
+ "Keepalive timer value in seconds")
+{
+ uint32_t timer;
+
+ timer = atoi (argv[0]);
+
+ zfpm_g->keepalive_ivl = timer;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN ( no_fpm_keepalive_timer,
+ no_fpm_keepalive_timer_cmd,
+ "no fpm keepalive timer <1-65535>",
+ NO_STR
+ FPM_STR
+ "Keepalive configuration\n"
+ "Keepalive timer\n"
+ "Keepalive timer value in seconds")
+{
+ uint32_t timer;
+
+ timer = atoi (argv[0]);
+
+ if (zfpm_g->keepalive_ivl != timer) {
+ return CMD_ERR_NO_MATCH;
+ }
+
+ zfpm_g->keepalive_ivl = ZFPM_KEEPALIVE_IVL_SECS;
+
+ return CMD_SUCCESS;
+}
+
/**
- * fpm_remote_srv_write
+ * zfpm_connection_config_write
*
- * Module to write remote fpm connection
- *
- * Returns ZERO on success.
+ * Writes connection-related configuration to vty
*/
-
-int fpm_remote_srv_write (struct vty *vty )
+static int
+zfpm_connection_config_write (struct vty *vty )
{
struct in_addr in;
@@ -1601,6 +1737,42 @@
return 0;
}
+/*
+ * zfpm_ka_config_write
+ *
+ * Writes keepalive-related configuration to vty
+ */
+static int
+zfpm_ka_config_write (struct vty *vty)
+{
+ if (zfpm_g->keepalive_ivl != ZFPM_KEEPALIVE_IVL_SECS) {
+ vty_out (vty, "fpm keepalive timer %d%s", zfpm_g->keepalive_ivl, VTY_NEWLINE);
+ }
+
+ return 0;
+}
+
+/*
+ * function to write the fpm config info to vty
+ */
+static int
+zfpm_vty_config_write (struct vty *vty)
+{
+ zfpm_connection_config_write (vty);
+ zfpm_ka_config_write (vty);
+ return 0;
+}
+
+/*
+ * Zebra node.
+ * TODO probably shouldn't use this, should define an FPM node
+ */
+static struct cmd_node zebra_node =
+{
+ ZEBRA_NODE,
+ "",
+ 1
+};
/**
* zfpm_init
@@ -1645,9 +1817,15 @@
install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd);
install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd);
+ install_element (CONFIG_NODE, &fpm_keepalive_timer_cmd);
+ install_element (CONFIG_NODE, &no_fpm_keepalive_timer_cmd);
install_element (CONFIG_NODE, &fpm_remote_ip_cmd);
install_element (CONFIG_NODE, &no_fpm_remote_ip_cmd);
+ install_node (&zebra_node, zfpm_vty_config_write);
+
+ zfpm_g->enabled = enable;
+
if (!enable) {
return 1;
}
@@ -1660,6 +1838,9 @@
zfpm_g->fpm_port = port;
+ if (!zfpm_g->keepalive_ivl)
+ zfpm_g->keepalive_ivl = ZFPM_KEEPALIVE_IVL_SECS;
+
zfpm_g->obuf = stream_new (ZFPM_OBUF_SIZE);
zfpm_g->ibuf = stream_new (ZFPM_IBUF_SIZE);
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 4b67c28..afd722a 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -1864,24 +1864,6 @@
1
};
-#ifdef HAVE_FPM
-/* function to write the fpm config info */
-static int
-config_write_fpm (struct vty *vty)
-{
- return
- fpm_remote_srv_write (vty);
-}
-
-/* Zebra node */
-static struct cmd_node zebra_node =
-{
- ZEBRA_NODE,
- "",
- 1
-};
-#endif
-
/* Initialisation of zebra and installation of commands. */
void
@@ -1893,9 +1875,6 @@
/* Install configuration write function. */
install_node (&table_node, config_write_table);
install_node (&forwarding_node, config_write_forwarding);
-#ifdef HAVE_FPM
- install_node (&zebra_node, config_write_fpm);
-#endif
install_element (VIEW_NODE, &show_ip_forwarding_cmd);
install_element (ENABLE_NODE, &show_ip_forwarding_cmd);