From 04b02fda9ff706fd53fbd17fe1700f567b1575b0 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 19 May 2015 17:47:22 -0700 Subject: [PATCH] zebra: zebra-client-info-detail.patch 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. --- zebra/redistribute.c | 58 ++++++++++--- zebra/zebra_rib.c | 5 +- zebra/zebra_rnh.c | 3 + zebra/zserv.c | 201 +++++++++++++++++++++++++++++++++++++++++-- zebra/zserv.h | 28 ++++++ 5 files changed, 273 insertions(+), 22 deletions(-) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 4767d9dbfe..19176db7fa 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -156,7 +156,10 @@ zebra_redistribute (struct zserv *client, int type) && 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 table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); @@ -167,7 +170,10 @@ zebra_redistribute (struct zserv *client, int type) && 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 */ } @@ -184,20 +190,32 @@ redistribute_add (struct prefix *p, struct rib *rib) if (client->redist_default || client->redist[rib->type]) { if (p->family == AF_INET) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); + { + client->redist_v4_add_cnt++; + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); + } #ifdef HAVE_IPV6 if (p->family == AF_INET6) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); + { + client->redist_v6_add_cnt++; + zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); + } #endif /* HAVE_IPV6 */ } } else if (client->redist[rib->type]) { if (p->family == AF_INET) - zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); + { + client->redist_v4_add_cnt++; + zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); + } #ifdef HAVE_IPV6 if (p->family == AF_INET6) - zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); + { + client->redist_v6_add_cnt++; + zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); + } #endif /* HAVE_IPV6 */ } } @@ -297,7 +315,9 @@ zebra_interface_up_update (struct interface *ifp) if (ifp->ptm_status || !ifp->ptm_enable) { for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) - zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + { + zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); + } } } @@ -312,7 +332,9 @@ zebra_interface_down_update (struct interface *ifp) 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. */ @@ -327,7 +349,10 @@ zebra_interface_add_update (struct interface *ifp) 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); + } } void @@ -341,7 +366,10 @@ zebra_interface_delete_update (struct interface *ifp) 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. */ @@ -370,7 +398,10 @@ zebra_interface_address_add_update (struct interface *ifp, 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. */ @@ -396,5 +427,8 @@ zebra_interface_address_delete_update (struct interface *ifp, 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); + } } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 9499e80422..a9f31b1a06 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2258,6 +2258,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) struct route_node *rn; struct rib *same; struct nexthop *nexthop; + int ret = 0; /* Lookup table. */ table = vrf_table (AFI_IP, safi, 0); @@ -2300,6 +2301,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) /* 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", @@ -2317,10 +2319,11 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib, safi_t safi) 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 67d27c8823..ed661d1d9c 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -657,6 +657,9 @@ send_client (struct rnh *rnh, struct zserv *client) 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 4fc9a80d9c..059fede6e3 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -100,6 +100,8 @@ zserv_flush_data(struct thread *thread) case BUFFER_EMPTY: break; } + + client->last_write_time = quagga_time(NULL); return 0; } @@ -108,6 +110,9 @@ zebra_server_send_message(struct zserv *client) { 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))) { @@ -129,6 +134,8 @@ zebra_server_send_message(struct zserv *client) zserv_flush_data, client, client->sock); break; } + + client->last_write_time = quagga_time(NULL); return 0; } @@ -194,6 +201,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_ADD); zserv_encode_interface (s, ifp); + client->ifadd_cnt++; return zebra_server_send_message(client); } @@ -213,6 +221,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_DELETE); zserv_encode_interface (s, ifp); + client->ifdel_cnt++; return zebra_server_send_message (client); } @@ -298,6 +307,7 @@ zsend_interface_address (int cmd, struct zserv *client, /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); + client->connected_rt_add_cnt++; return zebra_server_send_message(client); } @@ -463,6 +473,11 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) zserv_create_header (s, cmd); zserv_encode_interface (s, ifp); + if (cmd == ZEBRA_INTERFACE_UP) + client->ifup_cnt++; + else + client->ifdown_cnt++; + return zebra_server_send_message(client); } @@ -673,7 +688,7 @@ zsend_ipv6_nexthop_lookup (struct zserv *client, struct in6_addr *addr) } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } #endif /* HAVE_IPV6 */ @@ -775,6 +790,7 @@ zserv_nexthop_register (struct zserv *client, int sock, u_short length) if (connected) SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + client->nh_reg_time = quagga_time(NULL); zebra_add_rnh_client(rnh, client); } zebra_evaluate_rnh_table(0, AF_INET, 0); @@ -808,7 +824,10 @@ zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) 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; } @@ -872,7 +891,7 @@ zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) } stream_putw_at (s, 0, stream_get_endp (s)); - + return zebra_server_send_message(client); } @@ -973,7 +992,7 @@ zread_ipv4_add (struct zserv *client, u_short length) unsigned int ifindex; u_char ifname_len; safi_t safi; - + int ret; /* Get input stream. */ s = client->ibuf; @@ -1048,7 +1067,13 @@ zread_ipv4_add (struct zserv *client, u_short length) /* 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; } @@ -1137,6 +1162,7 @@ zread_ipv4_delete (struct zserv *client, u_short length) rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, client->rtm_table, api.safi); + client->v4_route_del_cnt++; return 0; } @@ -1185,6 +1211,7 @@ zread_ipv6_add (struct zserv *client, u_short length) safi_t safi; static struct in6_addr nexthops[MULTIPATH_NUM]; static unsigned int ifindices[MULTIPATH_NUM]; + int ret; /* Get input stream. */ s = client->ibuf; @@ -1283,7 +1310,13 @@ zread_ipv6_add (struct zserv *client, u_short length) /* Table */ rib->table=zebrad.rtm_table_default; - rib_add_ipv6_multipath (&p, rib, safi, ifindex); + ret = rib_add_ipv6_multipath (&p, rib, safi, ifindex); + /* Stats */ + if (ret > 0) + client->v6_route_add_cnt++; + else if (ret < 0) + client->v6_route_upd8_cnt++; + return 0; } @@ -1358,6 +1391,8 @@ zread_ipv6_delete (struct zserv *client, u_short length) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table, api.safi); else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table, api.safi); + + client->v6_route_del_cnt++; return 0; } @@ -1495,6 +1530,8 @@ zebra_client_create (int sock) /* Set table number. */ client->rtm_table = zebrad.rtm_table_default; + client->connect_time = quagga_time(NULL); + /* Add this client to linked list. */ listnode_add (zebrad.client_list, client); @@ -1607,6 +1644,9 @@ zebra_client_read (struct thread *thread) zlog_debug ("zebra message received [%s] %d", zserv_command_string (command), length); + client->last_read_time = quagga_time(NULL); + client->last_read_cmd = command; + switch (command) { case ZEBRA_ROUTER_ID_ADD: @@ -1863,6 +1903,127 @@ zebra_event (enum event event, int sock, struct zserv *client) } } +#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, @@ -1940,10 +2101,31 @@ DEFUN (show_zebra_client, 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; } @@ -2102,6 +2284,7 @@ zebra_init (void) 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 c5236367f4..589d2e56d2 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -72,6 +72,34 @@ struct zserv /* 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 */ -- 2.39.5