diff options
Diffstat (limited to 'zebra/zserv.c')
-rw-r--r-- | zebra/zserv.c | 562 |
1 files changed, 514 insertions, 48 deletions
diff --git a/zebra/zserv.c b/zebra/zserv.c index e624ef2f..0f8562e2 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -37,12 +37,14 @@ #include "network.h" #include "buffer.h" #include "vrf.h" +#include "nexthop.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" +#include "zebra/zebra_rnh.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; @@ -99,14 +101,19 @@ zserv_flush_data(struct thread *thread) case BUFFER_EMPTY: break; } + + client->last_write_time = quagga_time(NULL); return 0; } -static int +int 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))) { @@ -128,10 +135,12 @@ zebra_server_send_message(struct zserv *client) zserv_flush_data, client, client->sock); break; } + + client->last_write_time = quagga_time(NULL); return 0; } -static void +void zserv_create_header (struct stream *s, uint16_t cmd, vrf_id_t vrf_id) { /* length placeholder, caller can update */ @@ -189,6 +198,7 @@ zsend_interface_add (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); zserv_encode_interface (s, ifp); + client->ifadd_cnt++; return zebra_server_send_message(client); } @@ -208,6 +218,7 @@ zsend_interface_delete (struct zserv *client, struct interface *ifp) zserv_create_header (s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); zserv_encode_interface (s, ifp); + client->ifdel_cnt++; return zebra_server_send_message (client); } @@ -293,9 +304,147 @@ 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); +} + +static int +zsend_interface_nbr_address (int cmd, struct zserv *client, + struct interface *ifp, struct nbr_connected *ifc) +{ + int blen; + struct stream *s; + struct prefix *p; + + /* Check this client need interface information. */ + if (! client->ifinfo) + return 0; + + s = client->obuf; + stream_reset (s); + + zserv_create_header (s, cmd, ifp->vrf_id); + stream_putl (s, ifp->ifindex); + + /* Prefix information. */ + p = ifc->address; + stream_putc (s, p->family); + blen = prefix_blen (p); + stream_put (s, &p->u.prefix, blen); + + /* + * XXX gnu version does not send prefixlen for ZEBRA_INTERFACE_ADDRESS_DELETE + * but zebra_interface_address_delete_read() in the gnu version + * expects to find it + */ + stream_putc (s, p->prefixlen); + + /* Write packet size. */ + stream_putw_at (s, 0, stream_get_endp (s)); + return zebra_server_send_message(client); } +/* Interface address addition. */ +static void +zebra_interface_nbr_address_add_update (struct interface *ifp, + struct nbr_connected *ifc) +{ + struct listnode *node, *nnode; + struct zserv *client; + struct prefix *p; + + if (IS_ZEBRA_DEBUG_EVENT) + { + char buf[INET6_ADDRSTRLEN]; + + p = ifc->address; + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_NBR_ADDRESS_ADD %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), + p->prefixlen, ifc->ifp->name); + } + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + if (client->ifinfo) + zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, ifp, ifc); +} + +/* Interface address deletion. */ +static void +zebra_interface_nbr_address_delete_update (struct interface *ifp, + struct nbr_connected *ifc) +{ + struct listnode *node, *nnode; + struct zserv *client; + struct prefix *p; + + if (IS_ZEBRA_DEBUG_EVENT) + { + char buf[INET6_ADDRSTRLEN]; + + p = ifc->address; + zlog_debug ("MESSAGE: ZEBRA_INTERFACE_NBR_ADDRESS_DELETE %s/%d on %s", + inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), + p->prefixlen, ifc->ifp->name); + } + + for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) + if (client->ifinfo) + zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc); +} + +/* Add new nbr connected IPv6 address if none exists already, or replace the + existing one if an ifc entry is found on the interface. */ +void +nbr_connected_replacement_add_ipv6 (struct interface *ifp, struct in6_addr *address, + u_char prefixlen) +{ + struct nbr_connected *ifc; + struct prefix p; + + p.family = AF_INET6; + IPV6_ADDR_COPY (&p.u.prefix, address); + p.prefixlen = prefixlen; + + if (nbr_connected_check(ifp, &p)) + return; + + if (!(ifc = listnode_head(ifp->nbr_connected))) + { + /* new addition */ + ifc = nbr_connected_new (); + ifc->address = prefix_new(); + ifc->ifp = ifp; + listnode_add (ifp->nbr_connected, ifc); + } + + prefix_copy(ifc->address, &p); + + zebra_interface_nbr_address_add_update (ifp, ifc); +} + +void +nbr_connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, + u_char prefixlen) +{ + struct nbr_connected *ifc; + struct prefix p; + + p.family = AF_INET6; + IPV6_ADDR_COPY (&p.u.prefix, address); + p.prefixlen = prefixlen; + + ifc = nbr_connected_check(ifp, &p); + if (!ifc) + return; + + listnode_delete (ifp->nbr_connected, ifc); + + zebra_interface_nbr_address_delete_update (ifp, ifc); + + nbr_connected_free (ifc); +} + /* * The cmd passed to zsend_interface_update may be ZEBRA_INTERFACE_UP or * ZEBRA_INTERFACE_DOWN. @@ -321,6 +470,11 @@ zsend_interface_update (int cmd, struct zserv *client, struct interface *ifp) 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); } @@ -453,6 +607,12 @@ zsend_route_multipath (int cmd, struct zserv *client, struct prefix *p, stream_putl (s, rib->metric); SET_FLAG (zapi_flags, ZAPI_MESSAGE_MTU); stream_putl (s, rib->mtu); + /* tag */ + if (rib->tag) + { + SET_FLAG(zapi_flags, ZAPI_MESSAGE_TAG); + stream_putw(s, rib->tag); + } } /* write real message flags value */ @@ -532,7 +692,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 */ @@ -548,7 +708,7 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr, struct nexthop *nexthop; /* Lookup nexthop - eBGP excluded */ - rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, 1, NULL, vrf_id); + rib = rib_match_ipv4_safi (addr, SAFI_UNICAST, NULL, vrf_id); /* Get output stream. */ s = client->obuf; @@ -677,6 +837,75 @@ zsend_ipv4_nexthop_lookup_mrib (struct zserv *client, struct in_addr addr, return zebra_server_send_message(client); } +/* Nexthop register */ +static int +zserv_nexthop_register (struct zserv *client, int sock, u_short length, vrf_id_t vrf_id) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + u_char connected; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("nexthop_register msg from client %s: length=%d\n", + zebra_route_string(client->proto), length); + + s = client->ibuf; + + while (l < length) + { + connected = stream_getc(s); + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + l += 4; + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + rnh = zebra_add_rnh(&p, 0); + if (connected) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + + client->nh_reg_time = quagga_time(NULL); + zebra_add_rnh_client(rnh, client, vrf_id); + } + zebra_evaluate_rnh_table(0, AF_INET, 0); + zebra_evaluate_rnh_table(0, AF_INET6, 0); + return 0; +} + +/* Nexthop register */ +static int +zserv_nexthop_unregister (struct zserv *client, int sock, u_short length) +{ + struct rnh *rnh; + struct stream *s; + struct prefix p; + u_short l = 0; + + if (IS_ZEBRA_DEBUG_NHT) + zlog_debug("nexthop_unregister msg from client %s: length=%d\n", + zebra_route_string(client->proto), length); + + s = client->ibuf; + + while (l < length) + { + (void)stream_getc(s); + p.family = stream_getw(s); + p.prefixlen = stream_getc(s); + l += 4; + stream_get(&p.u.prefix, s, PSIZE(p.prefixlen)); + l += PSIZE(p.prefixlen); + rnh = zebra_lookup_rnh(&p, 0); + if (rnh) + { + client->nh_dereg_time = quagga_time(NULL); + zebra_remove_rnh_client(rnh, client); + } + } + return 0; +} + static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p, vrf_id_t vrf_id) @@ -736,7 +965,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); } @@ -779,6 +1008,7 @@ zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id) struct listnode *cnode, *cnnode; struct interface *ifp; struct connected *c; + struct nbr_connected *nc; /* Interface information is needed. */ vrf_bitmap_set (client->ifinfo, vrf_id); @@ -799,6 +1029,13 @@ zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id) ifp, c) < 0)) return -1; } + for (ALL_LIST_ELEMENTS (ifp->nbr_connected, cnode, cnnode, nc)) + { + if (zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client, + ifp, nc) < 0) + return -1; + } + } return 0; } @@ -830,7 +1067,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) ifindex_t ifindex; u_char ifname_len; safi_t safi; - + int ret; /* Get input stream. */ s = client->ibuf; @@ -867,7 +1104,7 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); - nexthop_ifindex_add (rib, ifindex); + rib_nexthop_ifindex_add (rib, ifindex); break; case ZEBRA_NEXTHOP_IFNAME: ifname_len = stream_getc (s); @@ -875,18 +1112,18 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) break; case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); - nexthop_ipv4_add (rib, &nexthop, NULL); + rib_nexthop_ipv4_add (rib, &nexthop, NULL); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); ifindex = stream_getl (s); - nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); + rib_nexthop_ipv4_ifindex_add (rib, &nexthop, NULL, ifindex); break; case ZEBRA_NEXTHOP_IPV6: stream_forward_getp (s, IPV6_MAX_BYTELEN); break; case ZEBRA_NEXTHOP_BLACKHOLE: - nexthop_blackhole_add (rib); + rib_nexthop_blackhole_add (rib); break; } } @@ -902,10 +1139,19 @@ zread_ipv4_add (struct zserv *client, u_short length, vrf_id_t vrf_id) if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) rib->mtu = stream_getl (s); + /* Tag */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + rib->tag = stream_getw (s); /* 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; } @@ -986,8 +1232,15 @@ zread_ipv4_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) else api.metric = 0; + /* tag */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + rib_delete_ipv4 (api.type, api.flags, &p, nexthop_p, ifindex, vrf_id, api.safi); + client->v4_route_del_cnt++; return 0; } @@ -1040,34 +1293,51 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { int i; struct stream *s; - struct zapi_ipv6 api; struct in6_addr nexthop; - unsigned long ifindex; + struct rib *rib; + u_char message; + u_char gateway_num; + u_char nexthop_type; struct prefix_ipv6 p; - + safi_t safi; + static struct in6_addr nexthops[MULTIPATH_NUM]; + static unsigned int ifindices[MULTIPATH_NUM]; + int ret; + + /* Get input stream. */ s = client->ibuf; - ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + /* Allocate new rib. */ + rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); + /* Type, flags, message. */ - api.type = stream_getc (s); - api.flags = stream_getc (s); - api.message = stream_getc (s); - api.safi = stream_getw (s); + rib->type = stream_getc (s); + rib->flags = stream_getc (s); + message = stream_getc (s); + safi = stream_getw (s); + rib->uptime = time (NULL); - /* IPv4 prefix. */ + /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); - /* Nexthop, ifindex, distance, metric. */ - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) + /* We need to give nh-addr, nh-ifindex with the same next-hop object + * to the rib to ensure that IPv6 multipathing works; need to coalesce + * these. Clients should send the same number of paired set of + * next-hop-addr/next-hop-ifindices. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_NEXTHOP)) { - u_char nexthop_type; + int nh_count = 0; + int if_count = 0; + int max_nh_if = 0; + unsigned int ifindex; - api.nexthop_num = stream_getc (s); - for (i = 0; i < api.nexthop_num; i++) + gateway_num = stream_getc (s); + for (i = 0; i < gateway_num; i++) { nexthop_type = stream_getc (s); @@ -1075,37 +1345,64 @@ zread_ipv6_add (struct zserv *client, u_short length, vrf_id_t vrf_id) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop, s, 16); + if (nh_count < MULTIPATH_NUM) { + nexthops[nh_count++] = nexthop; + } break; case ZEBRA_NEXTHOP_IFINDEX: ifindex = stream_getl (s); + if (if_count < MULTIPATH_NUM) { + ifindices[if_count++] = ifindex; + } break; + case ZEBRA_NEXTHOP_BLACKHOLE: + rib_nexthop_blackhole_add (rib); + break; + } + } + + max_nh_if = (nh_count > if_count) ? nh_count : if_count; + for (i = 0; i < max_nh_if; i++) + { + if ((i < nh_count) && !IN6_IS_ADDR_UNSPECIFIED (&nexthops[i])) + { + if ((i < if_count) && ifindices[i]) + rib_nexthop_ipv6_ifindex_add (rib, &nexthops[i], ifindices[i]); + else + rib_nexthop_ipv6_add (rib, &nexthops[i]); + } + else + { + if ((i < if_count) && ifindices[i]) + rib_nexthop_ifindex_add (rib, ifindices[i]); } } } - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) - api.distance = stream_getc (s); - else - api.distance = 0; + /* Distance. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) + rib->distance = stream_getc (s); - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) - api.metric = stream_getl (s); - else - api.metric = 0; + /* Metric. */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) + rib->metric = stream_getl (s); + + if (CHECK_FLAG (message, ZAPI_MESSAGE_MTU)) + rib->mtu = stream_getl (s); + + /* Tag */ + if (CHECK_FLAG (message, ZAPI_MESSAGE_TAG)) + rib->tag = stream_getw (s); + + /* Table */ + rib->table=zebrad.rtm_table_default; + 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++; - if (CHECK_FLAG (api.message, ZAPI_MESSAGE_MTU)) - api.mtu = stream_getl (s); - else - api.mtu = 0; - - if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) - rib_add_ipv6 (api.type, api.flags, &p, NULL, ifindex, - vrf_id, zebrad.rtm_table_default, api.metric, - api.mtu, api.distance, api.safi); - else - rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, - vrf_id, zebrad.rtm_table_default, api.metric, - api.mtu, api.distance, api.safi); return 0; } @@ -1158,21 +1455,32 @@ zread_ipv6_delete (struct zserv *client, u_short length, vrf_id_t vrf_id) } } + /* Distance. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; + + /* Metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; + /* tag */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG)) + api.tag = stream_getw (s); + else + api.tag = 0; + if (IN6_IS_ADDR_UNSPECIFIED (&nexthop)) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, vrf_id, api.safi); else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, vrf_id, api.safi); + + client->v6_route_del_cnt++; return 0; } @@ -1236,6 +1544,7 @@ zread_hello (struct zserv *client) client->sock); route_type_oaths[proto] = client->sock; + client->proto = proto; } } @@ -1276,6 +1585,9 @@ zebra_score_rib (int client_sock) static void zebra_client_close (struct zserv *client) { + zebra_cleanup_rnh_client(0, AF_INET, client); + zebra_cleanup_rnh_client(0, AF_INET6, client); + /* Close file descriptor. */ if (client->sock) { @@ -1329,6 +1641,7 @@ zebra_client_create (int sock) 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); @@ -1444,6 +1757,9 @@ zebra_client_read (struct thread *thread) 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: @@ -1503,6 +1819,11 @@ zebra_client_read (struct thread *thread) break; case ZEBRA_VRF_UNREGISTER: zread_vrf_unregister (client, length, vrf_id); + case ZEBRA_NEXTHOP_REGISTER: + zserv_nexthop_register(client, sock, length, vrf_id); + break; + case ZEBRA_NEXTHOP_UNREGISTER: + zserv_nexthop_unregister(client, sock, length); break; default: zlog_info ("Zebra received unknown command %d", command); @@ -1701,6 +2022,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, @@ -1778,8 +2220,31 @@ DEFUN (show_zebra_client, struct zserv *client; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) - vty_out (vty, "Client fd %d%s", 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; } @@ -1938,6 +2403,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); |