zebra: Gather and display detailed info about clients of Zebra
The display of zebra client info is rather paltry: just the name and the FD.
For troubleshooting and general helpfulness, its useful to gather more info
about each client and display that. This patch does just that.
Signed-off-by: Dinesh Dutt <ddutt@cumulusnetworks.com>
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 6c54917..a7a6b25 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -159,7 +159,10 @@
&& newrib->type == type
&& newrib->distance != DISTANCE_INFINITY
&& zebra_check_addr (&rn->p))
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+ {
+ client->redist_v4_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+ }
}
#ifdef HAVE_IPV6
@@ -171,7 +174,10 @@
&& newrib->type == type
&& newrib->distance != DISTANCE_INFINITY
&& zebra_check_addr (&rn->p))
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+ {
+ client->redist_v6_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+ }
#endif /* HAVE_IPV6 */
}
@@ -188,11 +194,15 @@
|| vrf_bitmap_check (client->redist[rib->type], rib->vrf_id))
{
if (p->family == AF_INET)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
-#ifdef HAVE_IPV6
+ {
+ client->redist_v4_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
+ }
if (p->family == AF_INET6)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
-#endif /* HAVE_IPV6 */
+ {
+ client->redist_v6_add_cnt++;
+ zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
+ }
}
}
}
@@ -299,7 +309,9 @@
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name);
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
- zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ {
+ zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ }
}
/* Interface information update. */
@@ -315,7 +327,8 @@
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo)
{
- zsend_interface_add (client, ifp);
+ client->ifadd_cnt++;
+ zsend_interface_add (client, ifp);
zsend_interface_link_params (client, ifp);
}
}
@@ -331,7 +344,10 @@
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo)
- zsend_interface_delete (client, ifp);
+ {
+ client->ifdel_cnt++;
+ zsend_interface_delete (client, ifp);
+ }
}
/* Interface address addition. */
@@ -360,7 +376,10 @@
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc);
+ {
+ client->connected_rt_add_cnt++;
+ zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc);
+ }
}
/* Interface address deletion. */
@@ -386,7 +405,10 @@
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc);
+ {
+ client->connected_rt_del_cnt++;
+ zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc);
+ }
}
/* Interface parameters update */
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 405528c..abb9560 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1910,6 +1910,7 @@
struct route_node *rn;
struct rib *same;
struct nexthop *nexthop;
+ int ret = 0;
/* Lookup table. */
table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id);
@@ -1952,6 +1953,7 @@
/* Link new rib to node.*/
rib_addnode (rn, rib);
+ ret = 1;
if (IS_ZEBRA_DEBUG_RIB)
{
zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry",
@@ -1969,10 +1971,11 @@
rib_dump (p, same);
}
rib_delnode (rn, same);
+ ret = -1;
}
route_unlock_node (rn);
- return 0;
+ return ret;
}
/* XXX factor with rib_delete_ipv6 */
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 3e02812..db2a34d 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -531,6 +531,9 @@
stream_putc (s, 0);
}
stream_putw_at (s, 0, stream_get_endp (s));
+
+ client->nh_last_upd_time = quagga_time(NULL);
+ client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
return zebra_server_send_message(client);
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 2319a06..4a8b55f 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -101,6 +101,8 @@
case BUFFER_EMPTY:
break;
}
+
+ client->last_write_time = quagga_time(NULL);
return 0;
}
@@ -109,6 +111,9 @@
{
if (client->t_suicide)
return -1;
+
+ stream_set_getp(client->obuf, 0);
+ client->last_write_cmd = stream_getw_from(client->obuf, 4);
switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf),
stream_get_endp(client->obuf)))
{
@@ -130,6 +135,8 @@
zserv_flush_data, client, client->sock);
break;
}
+
+ client->last_write_time = quagga_time(NULL);
return 0;
}
@@ -201,6 +208,7 @@
zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id);
zserv_encode_interface (s, ifp);
+ client->ifadd_cnt++;
return zebra_server_send_message(client);
}
@@ -220,6 +228,7 @@
zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id);
zserv_encode_interface (s, ifp);
+ client->ifdel_cnt++;
return zebra_server_send_message (client);
}
@@ -334,6 +343,7 @@
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
+ client->connected_rt_add_cnt++;
return zebra_server_send_message(client);
}
@@ -362,6 +372,11 @@
zserv_create_header (s, cmd, ifp->vrf_id);
zserv_encode_interface (s, ifp);
+ if (cmd == ZEBRA_INTERFACE_UP)
+ client->ifup_cnt++;
+ else
+ client->ifdown_cnt++;
+
return zebra_server_send_message(client);
}
@@ -579,7 +594,7 @@
}
stream_putw_at (s, 0, stream_get_endp (s));
-
+
return zebra_server_send_message(client);
}
#endif /* HAVE_IPV6 */
@@ -748,6 +763,8 @@
stream_get(&p.u.prefix, s, PSIZE(p.prefixlen));
l += PSIZE(p.prefixlen);
rnh = zebra_add_rnh(&p, 0);
+
+ client->nh_reg_time = quagga_time(NULL);
zebra_add_rnh_client(rnh, client, vrf_id);
}
zebra_evaluate_rnh_table(0, AF_INET);
@@ -779,7 +796,10 @@
l += PSIZE(p.prefixlen);
rnh = zebra_lookup_rnh(&p, 0);
if (rnh)
- zebra_remove_rnh_client(rnh, client);
+ {
+ client->nh_dereg_time = quagga_time(NULL);
+ zebra_remove_rnh_client(rnh, client);
+ }
}
return 0;
}
@@ -843,7 +863,7 @@
}
stream_putw_at (s, 0, stream_get_endp (s));
-
+
return zebra_server_send_message(client);
}
@@ -937,7 +957,7 @@
ifindex_t ifindex;
u_char ifname_len;
safi_t safi;
-
+ int ret;
/* Get input stream. */
s = client->ibuf;
@@ -1015,7 +1035,13 @@
/* Table */
rib->table=zebrad.rtm_table_default;
- rib_add_ipv4_multipath (&p, rib, safi);
+ ret = rib_add_ipv4_multipath (&p, rib, safi);
+
+ /* Stats */
+ if (ret > 0)
+ client->v4_route_add_cnt++;
+ else if (ret < 0)
+ client->v4_route_upd8_cnt++;
return 0;
}
@@ -1104,6 +1130,7 @@
rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex,
vrf_id, api.safi);
+ client->v4_route_del_cnt++;
return 0;
}
@@ -1165,6 +1192,7 @@
safi_t safi;
static struct in6_addr nexthops[MULTIPATH_NUM];
static unsigned int ifindices[MULTIPATH_NUM];
+ int ret;
/* Get input stream. */
s = client->ibuf;
@@ -1255,7 +1283,13 @@
/* Table */
rib->table=zebrad.rtm_table_default;
- rib_add_ipv6_multipath (&p, rib, safi);
+ ret = rib_add_ipv6_multipath (&p, rib, safi);
+ /* Stats */
+ if (ret > 0)
+ client->v6_route_add_cnt++;
+ else if (ret < 0)
+ client->v6_route_upd8_cnt++;
+
return 0;
}
@@ -1332,6 +1366,8 @@
else
rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id,
api.safi);
+
+ client->v6_route_del_cnt++;
return 0;
}
@@ -1492,6 +1528,7 @@
client->redist_default = vrf_bitmap_init ();
client->ifinfo = vrf_bitmap_init ();
client->ridinfo = vrf_bitmap_init ();
+ client->connect_time = quagga_time(NULL);
/* Add this client to linked list. */
listnode_add (zebrad.client_list, client);
@@ -1607,6 +1644,9 @@
zlog_debug ("zebra message received [%s] %d in VRF %u",
zserv_command_string (command), length, vrf_id);
+ client->last_read_time = quagga_time(NULL);
+ client->last_read_cmd = command;
+
switch (command)
{
case ZEBRA_ROUTER_ID_ADD:
@@ -1869,6 +1909,127 @@
}
}
+#define ZEBRA_TIME_BUF 32
+static char *
+zserv_time_buf(time_t *time1, char *buf, int buflen)
+{
+ struct tm *tm;
+ time_t now;
+
+ assert (buf != NULL);
+ assert (buflen >= ZEBRA_TIME_BUF);
+ assert (time1 != NULL);
+
+ if (!*time1)
+ {
+ snprintf(buf, buflen, "never ");
+ return (buf);
+ }
+
+ now = quagga_time(NULL);
+ now -= *time1;
+ tm = gmtime(&now);
+
+ /* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND 60*60*24*7
+
+ if (now < ONE_DAY_SECOND)
+ snprintf (buf, buflen, "%02d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ else if (now < ONE_WEEK_SECOND)
+ snprintf (buf, buflen, "%dd%02dh%02dm",
+ tm->tm_yday, tm->tm_hour, tm->tm_min);
+ else
+ snprintf (buf, buflen, "%02dw%dd%02dh",
+ tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
+ return buf;
+}
+
+static void
+zebra_show_client_detail (struct vty *vty, struct zserv *client)
+{
+ char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
+ char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
+
+ vty_out (vty, "Client: %s %s",
+ zebra_route_string(client->proto), VTY_NEWLINE);
+ vty_out (vty, "------------------------ %s", VTY_NEWLINE);
+ vty_out (vty, "FD: %d %s", client->sock, VTY_NEWLINE);
+ vty_out (vty, "Route Table ID: %d %s", client->rtm_table, VTY_NEWLINE);
+
+ vty_out (vty, "Connect Time: %s %s",
+ zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ if (client->nh_reg_time)
+ {
+ vty_out (vty, "Nexthop Registry Time: %s %s",
+ zserv_time_buf(&client->nh_reg_time, nhbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ if (client->nh_last_upd_time)
+ vty_out (vty, "Nexthop Last Update Time: %s %s",
+ zserv_time_buf(&client->nh_last_upd_time, mbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ else
+ vty_out (vty, "No Nexthop Update sent%s", VTY_NEWLINE);
+ }
+ else
+ vty_out (vty, "Not registered for Nexthop Updates%s", VTY_NEWLINE);
+
+ vty_out (vty, "Last Msg Rx Time: %s %s",
+ zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ vty_out (vty, "Last Msg Tx Time: %s %s",
+ zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF),
+ VTY_NEWLINE);
+ if (client->last_read_time)
+ vty_out (vty, "Last Rcvd Cmd: %s %s",
+ zserv_command_string(client->last_read_cmd), VTY_NEWLINE);
+ if (client->last_write_time)
+ vty_out (vty, "Last Sent Cmd: %s %s",
+ zserv_command_string(client->last_write_cmd), VTY_NEWLINE);
+ vty_out (vty, "%s", VTY_NEWLINE);
+
+ vty_out (vty, "Type Add Update Del %s", VTY_NEWLINE);
+ vty_out (vty, "================================================== %s", VTY_NEWLINE);
+ vty_out (vty, "IPv4 %-12d%-12d%-12d%s", client->v4_route_add_cnt,
+ client->v4_route_upd8_cnt, client->v4_route_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "IPv6 %-12d%-12d%-12d%s", client->v6_route_add_cnt,
+ client->v6_route_upd8_cnt, client->v6_route_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "Redist:v4 %-12d%-12d%-12d%s", client->redist_v4_add_cnt, 0,
+ client->redist_v4_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "Redist:v6 %-12d%-12d%-12d%s", client->redist_v6_add_cnt, 0,
+ client->redist_v6_del_cnt, VTY_NEWLINE);
+ vty_out (vty, "Connected %-12d%-12d%-12d%s", client->ifadd_cnt, 0,
+ client->ifdel_cnt, VTY_NEWLINE);
+ vty_out (vty, "Interface Up Notifications: %d%s", client->ifup_cnt,
+ VTY_NEWLINE);
+ vty_out (vty, "Interface Down Notifications: %d%s", client->ifdown_cnt,
+ VTY_NEWLINE);
+
+ vty_out (vty, "%s", VTY_NEWLINE);
+ return;
+}
+
+static void
+zebra_show_client_brief (struct vty *vty, struct zserv *client)
+{
+ char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
+ char wbuf[ZEBRA_TIME_BUF];
+
+ vty_out (vty, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d%s",
+ zebra_route_string(client->proto),
+ zserv_time_buf(&client->connect_time, cbuf, ZEBRA_TIME_BUF),
+ zserv_time_buf(&client->last_read_time, rbuf, ZEBRA_TIME_BUF),
+ zserv_time_buf(&client->last_write_time, wbuf, ZEBRA_TIME_BUF),
+ client->v4_route_add_cnt+client->v4_route_upd8_cnt,
+ client->v4_route_del_cnt,
+ client->v6_route_add_cnt+client->v6_route_upd8_cnt,
+ client->v6_route_del_cnt, VTY_NEWLINE);
+
+}
+
+
/* Display default rtm_table for all clients. */
DEFUN (show_table,
show_table_cmd,
@@ -1946,13 +2107,34 @@
struct zserv *client;
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
- vty_out (vty, "Client %s fd %d%s",
- zebra_route_string(client->proto), client->sock,
- VTY_NEWLINE);
+ zebra_show_client_detail(vty, client);
return CMD_SUCCESS;
}
+/* This command is for debugging purpose. */
+DEFUN (show_zebra_client_summary,
+ show_zebra_client_summary_cmd,
+ "show zebra client summary",
+ SHOW_STR
+ "Zebra information brief"
+ "Client information brief")
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ vty_out (vty, "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes %s",
+ VTY_NEWLINE);
+ vty_out (vty,"--------------------------------------------------------------------------------%s",
+ VTY_NEWLINE);
+
+ for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
+ zebra_show_client_brief(vty, client);
+
+ vty_out (vty, "Routes column shows (added+updated)/deleted%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
/* Table configuration write function. */
static int
config_write_table (struct vty *vty)
@@ -2128,6 +2310,7 @@
install_element (CONFIG_NODE, &ip_forwarding_cmd);
install_element (CONFIG_NODE, &no_ip_forwarding_cmd);
install_element (ENABLE_NODE, &show_zebra_client_cmd);
+ install_element (ENABLE_NODE, &show_zebra_client_summary_cmd);
#ifdef HAVE_NETLINK
install_element (VIEW_NODE, &show_table_cmd);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 7a2b4a1..4af92f0 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -70,6 +70,34 @@
/* client's protocol */
u_char proto;
+
+ /* Statistics */
+ u_int32_t redist_v4_add_cnt;
+ u_int32_t redist_v4_del_cnt;
+ u_int32_t redist_v6_add_cnt;
+ u_int32_t redist_v6_del_cnt;
+ u_int32_t v4_route_add_cnt;
+ u_int32_t v4_route_upd8_cnt;
+ u_int32_t v4_route_del_cnt;
+ u_int32_t v6_route_add_cnt;
+ u_int32_t v6_route_del_cnt;
+ u_int32_t v6_route_upd8_cnt;
+ u_int32_t connected_rt_add_cnt;
+ u_int32_t connected_rt_del_cnt;
+ u_int32_t ifup_cnt;
+ u_int32_t ifdown_cnt;
+ u_int32_t ifadd_cnt;
+ u_int32_t ifdel_cnt;
+
+ time_t connect_time;
+ time_t last_read_time;
+ time_t last_write_time;
+ time_t nh_reg_time;
+ time_t nh_dereg_time;
+ time_t nh_last_upd_time;
+
+ int last_read_cmd;
+ int last_write_cmd;
};
/* Zebra instance */