4 * Copyright (C) 1997-1999 Kunihiro Ishiguro
5 * Copyright (C) 2015-2018 Cumulus Networks, Inc.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 /* clang-format off */
26 #include <errno.h> /* for errno */
27 #include <netinet/in.h> /* for sockaddr_in */
28 #include <stdint.h> /* for uint8_t */
29 #include <stdio.h> /* for snprintf */
30 #include <sys/socket.h> /* for sockaddr_storage, AF_UNIX, accept... */
31 #include <sys/stat.h> /* for umask, mode_t */
32 #include <sys/un.h> /* for sockaddr_un */
33 #include <time.h> /* for NULL, tm, gmtime, time_t */
34 #include <unistd.h> /* for close, unlink, ssize_t */
36 #include "lib/buffer.h" /* for BUFFER_EMPTY, BUFFER_ERROR, BUFFE... */
37 #include "lib/command.h" /* for vty, install_element, CMD_SUCCESS... */
38 #include "lib/hook.h" /* for DEFINE_HOOK, DEFINE_KOOH, hook_call */
39 #include "lib/linklist.h" /* for ALL_LIST_ELEMENTS_RO, ALL_LIST_EL... */
40 #include "lib/libfrr.h" /* for frr_zclient_addr */
41 #include "lib/log.h" /* for zlog_warn, zlog_debug, safe_strerror */
42 #include "lib/memory.h" /* for MTYPE_TMP, XCALLOC, XFREE */
43 #include "lib/monotime.h" /* for monotime, ONE_DAY_SECOND, ONE_WEE... */
44 #include "lib/network.h" /* for set_nonblocking */
45 #include "lib/privs.h" /* for zebra_privs_t, ZPRIVS_LOWER, ZPRI... */
46 #include "lib/route_types.h" /* for ZEBRA_ROUTE_MAX */
47 #include "lib/sockopt.h" /* for setsockopt_so_recvbuf, setsockopt... */
48 #include "lib/sockunion.h" /* for sockopt_reuseaddr, sockopt_reuseport */
49 #include "lib/stream.h" /* for STREAM_SIZE, stream (ptr only), ... */
50 #include "lib/thread.h" /* for thread (ptr only), THREAD_ARG, ... */
51 #include "lib/vrf.h" /* for vrf_info_lookup, VRF_DEFAULT */
52 #include "lib/vty.h" /* for vty_out, vty (ptr only) */
53 #include "lib/zassert.h" /* for assert */
54 #include "lib/zclient.h" /* for zmsghdr, ZEBRA_HEADER_SIZE, ZEBRA... */
56 #include "zebra/debug.h" /* for various debugging macros */
57 #include "zebra/rib.h" /* for rib_score_proto */
58 #include "zebra/zapi_msg.h" /* for zserv_handle_commands */
59 #include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */
60 #include "zebra/zserv.h" /* for zserv */
63 /* Event list of zebra. */
64 enum event
{ ZEBRA_READ
, ZEBRA_WRITE
};
66 extern struct zebra_privs_t zserv_privs
;
67 /* post event into client */
68 static void zebra_event(struct zserv
*client
, enum event event
);
71 /* Public interface --------------------------------------------------------- */
73 int zebra_server_send_message(struct zserv
*client
, struct stream
*msg
)
75 stream_fifo_push(client
->obuf_fifo
, msg
);
76 zebra_event(client
, ZEBRA_WRITE
);
80 /* Lifecycle ---------------------------------------------------------------- */
82 /* Hooks for client connect / disconnect */
83 DEFINE_HOOK(zapi_client_connect
, (struct zserv
* client
), (client
));
84 DEFINE_KOOH(zapi_client_close
, (struct zserv
* client
), (client
));
86 /* free zebra client information. */
87 static void zebra_client_free(struct zserv
*client
)
89 hook_call(zapi_client_close
, client
);
91 /* Close file descriptor. */
93 unsigned long nroutes
;
96 nroutes
= rib_score_proto(client
->proto
, client
->instance
);
98 "client %d disconnected. %lu %s routes removed from the rib",
99 client
->sock
, nroutes
,
100 zebra_route_string(client
->proto
));
104 /* Free stream buffers. */
105 if (client
->ibuf_work
)
106 stream_free(client
->ibuf_work
);
107 if (client
->obuf_work
)
108 stream_free(client
->obuf_work
);
109 if (client
->ibuf_fifo
)
110 stream_fifo_free(client
->ibuf_fifo
);
111 if (client
->obuf_fifo
)
112 stream_fifo_free(client
->obuf_fifo
);
114 buffer_free(client
->wb
);
116 /* Release threads. */
118 thread_cancel(client
->t_read
);
120 thread_cancel(client
->t_write
);
121 if (client
->t_suicide
)
122 thread_cancel(client
->t_suicide
);
125 for (afi_t afi
= AFI_IP
; afi
< AFI_MAX
; afi
++)
126 for (int i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
127 vrf_bitmap_free(client
->redist
[afi
][i
]);
129 vrf_bitmap_free(client
->redist_default
);
130 vrf_bitmap_free(client
->ifinfo
);
131 vrf_bitmap_free(client
->ridinfo
);
133 XFREE(MTYPE_TMP
, client
);
137 * Called from client thread to terminate itself.
139 static void zebra_client_close(struct zserv
*client
)
141 listnode_delete(zebrad
.client_list
, client
);
142 zebra_client_free(client
);
145 /* Make new client. */
146 static void zebra_client_create(int sock
)
148 struct zserv
*client
;
152 client
= XCALLOC(MTYPE_TMP
, sizeof(struct zserv
));
154 /* Make client input/output buffer. */
156 client
->ibuf_fifo
= stream_fifo_new();
157 client
->obuf_fifo
= stream_fifo_new();
158 client
->ibuf_work
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
159 client
->obuf_work
= stream_new(ZEBRA_MAX_PACKET_SIZ
);
160 client
->wb
= buffer_new(0);
162 /* Set table number. */
163 client
->rtm_table
= zebrad
.rtm_table_default
;
165 client
->connect_time
= monotime(NULL
);
166 /* Initialize flags */
167 for (afi
= AFI_IP
; afi
< AFI_MAX
; afi
++)
168 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++)
169 client
->redist
[afi
][i
] = vrf_bitmap_init();
170 client
->redist_default
= vrf_bitmap_init();
171 client
->ifinfo
= vrf_bitmap_init();
172 client
->ridinfo
= vrf_bitmap_init();
174 /* by default, it's not a synchronous client */
175 client
->is_synchronous
= 0;
177 /* Add this client to linked list. */
178 listnode_add(zebrad
.client_list
, client
);
180 zebra_vrf_update_all(client
);
182 hook_call(zapi_client_connect
, client
);
184 /* start read loop */
185 zebra_event(client
, ZEBRA_READ
);
188 static int zserv_delayed_close(struct thread
*thread
)
190 struct zserv
*client
= THREAD_ARG(thread
);
192 client
->t_suicide
= NULL
;
193 zebra_client_close(client
);
198 * Log zapi message to zlog.
209 static void zserv_log_message(const char *errmsg
, struct stream
*msg
,
212 zlog_debug("Rx'd ZAPI message");
214 zlog_debug("%s", errmsg
);
216 zlog_debug(" Length: %d", hdr
->length
);
217 zlog_debug("Command: %s", zserv_command_string(hdr
->command
));
218 zlog_debug(" VRF: %u", hdr
->vrf_id
);
220 zlog_hexdump(msg
->data
, STREAM_READABLE(msg
));
223 static int zserv_flush_data(struct thread
*thread
)
225 struct zserv
*client
= THREAD_ARG(thread
);
227 client
->t_write
= NULL
;
228 if (client
->t_suicide
) {
229 zebra_client_close(client
);
232 switch (buffer_flush_available(client
->wb
, client
->sock
)) {
235 "%s: buffer_flush_available failed on zserv client fd %d, closing",
236 __func__
, client
->sock
);
237 zebra_client_close(client
);
241 client
->t_write
= NULL
;
242 thread_add_write(zebrad
.master
, zserv_flush_data
, client
,
243 client
->sock
, &client
->t_write
);
250 client
->last_write_time
= monotime(NULL
);
255 * Write a single packet.
257 static int zserv_write(struct thread
*thread
)
259 struct zserv
*client
= THREAD_ARG(thread
);
263 if (client
->t_suicide
)
266 if (client
->is_synchronous
)
269 msg
= stream_fifo_pop(client
->obuf_fifo
);
270 stream_set_getp(msg
, 0);
271 client
->last_write_cmd
= stream_getw_from(msg
, 6);
273 writerv
= buffer_write(client
->wb
, client
->sock
, STREAM_DATA(msg
),
274 stream_get_endp(msg
));
281 "%s: buffer_write failed to zserv client fd %d, closing",
282 __func__
, client
->sock
);
284 * Schedule a delayed close since many of the functions that
285 * call this one do not check the return code. They do not
286 * allow for the possibility that an I/O error may have caused
287 * the client to be deleted.
289 client
->t_suicide
= NULL
;
290 thread_add_event(zebrad
.master
, zserv_delayed_close
, client
, 0,
294 THREAD_OFF(client
->t_write
);
297 thread_add_write(zebrad
.master
, zserv_flush_data
, client
,
298 client
->sock
, &client
->t_write
);
302 if (client
->obuf_fifo
->count
)
303 zebra_event(client
, ZEBRA_WRITE
);
305 client
->last_write_time
= monotime(NULL
);
309 #if defined(HANDLE_ZAPI_FUZZING)
310 static void zserv_write_incoming(struct stream
*orig
, uint16_t command
)
312 char fname
[MAXPATHLEN
];
316 copy
= stream_dup(orig
);
317 stream_set_getp(copy
, 0);
319 zserv_privs
.change(ZPRIVS_RAISE
);
320 snprintf(fname
, MAXPATHLEN
, "%s/%u", DAEMON_VTY_DIR
, command
);
321 fd
= open(fname
, O_CREAT
| O_WRONLY
| O_EXCL
, 0644);
322 stream_flush(copy
, fd
);
324 zserv_privs
.change(ZPRIVS_LOWER
);
329 static int zserv_process_messages(struct thread
*thread
)
331 struct zserv
*client
= THREAD_ARG(thread
);
332 struct zebra_vrf
*zvrf
;
338 msg
= stream_fifo_pop(client
->ibuf_fifo
);
340 /* break if out of messages */
344 /* read & check header */
345 hdrvalid
= zapi_parse_header(msg
, &hdr
);
346 if (!hdrvalid
&& IS_ZEBRA_DEBUG_PACKET
&& IS_ZEBRA_DEBUG_RECV
) {
347 const char *emsg
= "Message has corrupt header";
348 zserv_log_message(emsg
, msg
, NULL
);
353 hdr
.length
-= ZEBRA_HEADER_SIZE
;
355 zvrf
= zebra_vrf_lookup_by_id(hdr
.vrf_id
);
356 if (!zvrf
&& IS_ZEBRA_DEBUG_PACKET
&& IS_ZEBRA_DEBUG_RECV
) {
357 const char *emsg
= "Message specifies unknown VRF";
358 zserv_log_message(emsg
, msg
, &hdr
);
363 /* process commands */
364 zserv_handle_commands(client
, &hdr
, msg
, zvrf
);
371 /* Handler of zebra service request. */
372 static int zserv_read(struct thread
*thread
)
375 struct zserv
*client
;
377 #if defined(HANDLE_ZAPI_FUZZING)
380 int packets
= zebrad
.packets_to_process
;
382 /* Get thread data. Reset reading thread because I'm running. */
383 sock
= THREAD_FD(thread
);
384 client
= THREAD_ARG(thread
);
386 if (client
->t_suicide
) {
387 zebra_client_close(client
);
397 already
= stream_get_endp(client
->ibuf_work
);
399 /* Read length and command (if we don't have it already). */
400 if (already
< ZEBRA_HEADER_SIZE
) {
401 nb
= stream_read_try(client
->ibuf_work
, sock
,
402 ZEBRA_HEADER_SIZE
- already
);
403 if ((nb
== 0 || nb
== -1) && IS_ZEBRA_DEBUG_EVENT
)
404 zlog_debug("connection closed socket [%d]",
406 if ((nb
== 0 || nb
== -1))
408 if (nb
!= (ssize_t
)(ZEBRA_HEADER_SIZE
- already
)) {
409 /* Try again later. */
412 already
= ZEBRA_HEADER_SIZE
;
415 /* Reset to read from the beginning of the incoming packet. */
416 stream_set_getp(client
->ibuf_work
, 0);
418 /* Fetch header values */
419 hdrvalid
= zapi_parse_header(client
->ibuf_work
, &hdr
);
422 snprintf(errmsg
, sizeof(errmsg
),
423 "%s: Message has corrupt header", __func__
);
424 zserv_log_message(errmsg
, client
->ibuf_work
, NULL
);
428 /* Validate header */
429 if (hdr
.marker
!= ZEBRA_HEADER_MARKER
430 || hdr
.version
!= ZSERV_VERSION
) {
432 errmsg
, sizeof(errmsg
),
433 "Message has corrupt header\n%s: socket %d version mismatch, marker %d, version %d",
434 __func__
, sock
, hdr
.marker
, hdr
.version
);
435 zserv_log_message(errmsg
, client
->ibuf_work
, &hdr
);
438 if (hdr
.length
< ZEBRA_HEADER_SIZE
) {
440 errmsg
, sizeof(errmsg
),
441 "Message has corrupt header\n%s: socket %d message length %u is less than header size %d",
442 __func__
, sock
, hdr
.length
, ZEBRA_HEADER_SIZE
);
443 zserv_log_message(errmsg
, client
->ibuf_work
, &hdr
);
446 if (hdr
.length
> STREAM_SIZE(client
->ibuf_work
)) {
448 errmsg
, sizeof(errmsg
),
449 "Message has corrupt header\n%s: socket %d message length %u exceeds buffer size %lu",
450 __func__
, sock
, hdr
.length
,
451 (unsigned long)STREAM_SIZE(client
->ibuf_work
));
455 /* Read rest of data. */
456 if (already
< hdr
.length
) {
457 nb
= stream_read_try(client
->ibuf_work
, sock
,
458 hdr
.length
- already
);
459 if ((nb
== 0 || nb
== -1) && IS_ZEBRA_DEBUG_EVENT
)
461 "connection closed [%d] when reading zebra data",
463 if ((nb
== 0 || nb
== -1))
465 if (nb
!= (ssize_t
)(hdr
.length
- already
)) {
466 /* Try again later. */
471 #if defined(HANDLE_ZAPI_FUZZING)
472 zserv_write_incoming(client
->ibuf_work
, command
);
475 /* Debug packet information. */
476 if (IS_ZEBRA_DEBUG_EVENT
)
477 zlog_debug("zebra message comes from socket [%d]",
480 if (IS_ZEBRA_DEBUG_PACKET
&& IS_ZEBRA_DEBUG_RECV
)
481 zserv_log_message(NULL
, client
->ibuf_work
, &hdr
);
483 client
->last_read_time
= monotime(NULL
);
484 client
->last_read_cmd
= hdr
.command
;
486 stream_set_getp(client
->ibuf_work
, 0);
487 struct stream
*msg
= stream_dup(client
->ibuf_work
);
489 stream_fifo_push(client
->ibuf_fifo
, msg
);
491 if (client
->t_suicide
)
495 stream_reset(client
->ibuf_work
);
498 if (IS_ZEBRA_DEBUG_PACKET
)
499 zlog_debug("Read %d packets",
500 zebrad
.packets_to_process
- packets
);
502 /* Schedule job to process those packets */
503 thread_add_event(zebrad
.master
, &zserv_process_messages
, client
, 0,
506 /* Reschedule ourselves */
507 zebra_event(client
, ZEBRA_READ
);
512 zebra_client_close(client
);
516 static void zebra_event(struct zserv
*client
, enum event event
)
520 thread_add_read(zebrad
.master
, zserv_read
, client
, client
->sock
,
524 thread_add_write(zebrad
.master
, zserv_write
, client
,
525 client
->sock
, &client
->t_write
);
530 /* Accept code of zebra server socket. */
531 static int zebra_accept(struct thread
*thread
)
535 struct sockaddr_in client
;
538 accept_sock
= THREAD_FD(thread
);
540 /* Reregister myself. */
541 thread_add_read(zebrad
.master
, zebra_accept
, NULL
, accept_sock
, NULL
);
543 len
= sizeof(struct sockaddr_in
);
544 client_sock
= accept(accept_sock
, (struct sockaddr
*)&client
, &len
);
546 if (client_sock
< 0) {
547 zlog_warn("Can't accept zebra socket: %s",
548 safe_strerror(errno
));
552 /* Make client socket non-blocking. */
553 set_nonblocking(client_sock
);
555 /* Create new zebra client. */
556 zebra_client_create(client_sock
);
561 /* Make zebra server socket, wiping any existing one (see bug #403). */
562 void zebra_zserv_socket_init(char *path
)
567 struct sockaddr_storage sa
;
570 if (!frr_zclient_addr(&sa
, &sa_len
, path
))
571 /* should be caught in zebra main() */
575 old_mask
= umask(0077);
577 /* Make UNIX domain socket. */
578 sock
= socket(sa
.ss_family
, SOCK_STREAM
, 0);
580 zlog_warn("Can't create zserv socket: %s",
581 safe_strerror(errno
));
583 "zebra can't provide full functionality due to above error");
587 if (sa
.ss_family
!= AF_UNIX
) {
588 sockopt_reuseaddr(sock
);
589 sockopt_reuseport(sock
);
591 struct sockaddr_un
*suna
= (struct sockaddr_un
*)&sa
;
592 if (suna
->sun_path
[0])
593 unlink(suna
->sun_path
);
596 zserv_privs
.change(ZPRIVS_RAISE
);
597 setsockopt_so_recvbuf(sock
, 1048576);
598 setsockopt_so_sendbuf(sock
, 1048576);
599 zserv_privs
.change(ZPRIVS_LOWER
);
601 if (sa
.ss_family
!= AF_UNIX
&& zserv_privs
.change(ZPRIVS_RAISE
))
602 zlog_err("Can't raise privileges");
604 ret
= bind(sock
, (struct sockaddr
*)&sa
, sa_len
);
606 zlog_warn("Can't bind zserv socket on %s: %s", path
,
607 safe_strerror(errno
));
609 "zebra can't provide full functionality due to above error");
613 if (sa
.ss_family
!= AF_UNIX
&& zserv_privs
.change(ZPRIVS_LOWER
))
614 zlog_err("Can't lower privileges");
616 ret
= listen(sock
, 5);
618 zlog_warn("Can't listen to zserv socket %s: %s", path
,
619 safe_strerror(errno
));
621 "zebra can't provide full functionality due to above error");
628 thread_add_read(zebrad
.master
, zebra_accept
, NULL
, sock
, NULL
);
631 #define ZEBRA_TIME_BUF 32
632 static char *zserv_time_buf(time_t *time1
, char *buf
, int buflen
)
638 assert(buflen
>= ZEBRA_TIME_BUF
);
639 assert(time1
!= NULL
);
642 snprintf(buf
, buflen
, "never ");
646 now
= monotime(NULL
);
650 if (now
< ONE_DAY_SECOND
)
651 snprintf(buf
, buflen
, "%02d:%02d:%02d", tm
->tm_hour
, tm
->tm_min
,
653 else if (now
< ONE_WEEK_SECOND
)
654 snprintf(buf
, buflen
, "%dd%02dh%02dm", tm
->tm_yday
, tm
->tm_hour
,
657 snprintf(buf
, buflen
, "%02dw%dd%02dh", tm
->tm_yday
/ 7,
658 tm
->tm_yday
- ((tm
->tm_yday
/ 7) * 7), tm
->tm_hour
);
662 static void zebra_show_client_detail(struct vty
*vty
, struct zserv
*client
)
664 char cbuf
[ZEBRA_TIME_BUF
], rbuf
[ZEBRA_TIME_BUF
];
665 char wbuf
[ZEBRA_TIME_BUF
], nhbuf
[ZEBRA_TIME_BUF
], mbuf
[ZEBRA_TIME_BUF
];
667 vty_out(vty
, "Client: %s", zebra_route_string(client
->proto
));
668 if (client
->instance
)
669 vty_out(vty
, " Instance: %d", client
->instance
);
672 vty_out(vty
, "------------------------ \n");
673 vty_out(vty
, "FD: %d \n", client
->sock
);
674 vty_out(vty
, "Route Table ID: %d \n", client
->rtm_table
);
676 vty_out(vty
, "Connect Time: %s \n",
677 zserv_time_buf(&client
->connect_time
, cbuf
, ZEBRA_TIME_BUF
));
678 if (client
->nh_reg_time
) {
679 vty_out(vty
, "Nexthop Registry Time: %s \n",
680 zserv_time_buf(&client
->nh_reg_time
, nhbuf
,
682 if (client
->nh_last_upd_time
)
683 vty_out(vty
, "Nexthop Last Update Time: %s \n",
684 zserv_time_buf(&client
->nh_last_upd_time
, mbuf
,
687 vty_out(vty
, "No Nexthop Update sent\n");
689 vty_out(vty
, "Not registered for Nexthop Updates\n");
691 vty_out(vty
, "Last Msg Rx Time: %s \n",
692 zserv_time_buf(&client
->last_read_time
, rbuf
, ZEBRA_TIME_BUF
));
693 vty_out(vty
, "Last Msg Tx Time: %s \n",
694 zserv_time_buf(&client
->last_write_time
, wbuf
, ZEBRA_TIME_BUF
));
695 if (client
->last_read_time
)
696 vty_out(vty
, "Last Rcvd Cmd: %s \n",
697 zserv_command_string(client
->last_read_cmd
));
698 if (client
->last_write_time
)
699 vty_out(vty
, "Last Sent Cmd: %s \n",
700 zserv_command_string(client
->last_write_cmd
));
703 vty_out(vty
, "Type Add Update Del \n");
704 vty_out(vty
, "================================================== \n");
705 vty_out(vty
, "IPv4 %-12d%-12d%-12d\n", client
->v4_route_add_cnt
,
706 client
->v4_route_upd8_cnt
, client
->v4_route_del_cnt
);
707 vty_out(vty
, "IPv6 %-12d%-12d%-12d\n", client
->v6_route_add_cnt
,
708 client
->v6_route_upd8_cnt
, client
->v6_route_del_cnt
);
709 vty_out(vty
, "Redist:v4 %-12d%-12d%-12d\n", client
->redist_v4_add_cnt
,
710 0, client
->redist_v4_del_cnt
);
711 vty_out(vty
, "Redist:v6 %-12d%-12d%-12d\n", client
->redist_v6_add_cnt
,
712 0, client
->redist_v6_del_cnt
);
713 vty_out(vty
, "Connected %-12d%-12d%-12d\n", client
->ifadd_cnt
, 0,
715 vty_out(vty
, "BFD peer %-12d%-12d%-12d\n", client
->bfd_peer_add_cnt
,
716 client
->bfd_peer_upd8_cnt
, client
->bfd_peer_del_cnt
);
717 vty_out(vty
, "Interface Up Notifications: %d\n", client
->ifup_cnt
);
718 vty_out(vty
, "Interface Down Notifications: %d\n", client
->ifdown_cnt
);
719 vty_out(vty
, "VNI add notifications: %d\n", client
->vniadd_cnt
);
720 vty_out(vty
, "VNI delete notifications: %d\n", client
->vnidel_cnt
);
721 vty_out(vty
, "L3-VNI add notifications: %d\n", client
->l3vniadd_cnt
);
722 vty_out(vty
, "L3-VNI delete notifications: %d\n", client
->l3vnidel_cnt
);
723 vty_out(vty
, "MAC-IP add notifications: %d\n", client
->macipadd_cnt
);
724 vty_out(vty
, "MAC-IP delete notifications: %d\n", client
->macipdel_cnt
);
730 static void zebra_show_client_brief(struct vty
*vty
, struct zserv
*client
)
732 char cbuf
[ZEBRA_TIME_BUF
], rbuf
[ZEBRA_TIME_BUF
];
733 char wbuf
[ZEBRA_TIME_BUF
];
735 vty_out(vty
, "%-8s%12s %12s%12s%8d/%-8d%8d/%-8d\n",
736 zebra_route_string(client
->proto
),
737 zserv_time_buf(&client
->connect_time
, cbuf
, ZEBRA_TIME_BUF
),
738 zserv_time_buf(&client
->last_read_time
, rbuf
, ZEBRA_TIME_BUF
),
739 zserv_time_buf(&client
->last_write_time
, wbuf
, ZEBRA_TIME_BUF
),
740 client
->v4_route_add_cnt
+ client
->v4_route_upd8_cnt
,
741 client
->v4_route_del_cnt
,
742 client
->v6_route_add_cnt
+ client
->v6_route_upd8_cnt
,
743 client
->v6_route_del_cnt
);
746 struct zserv
*zebra_find_client(uint8_t proto
, unsigned short instance
)
748 struct listnode
*node
, *nnode
;
749 struct zserv
*client
;
751 for (ALL_LIST_ELEMENTS(zebrad
.client_list
, node
, nnode
, client
)) {
752 if (client
->proto
== proto
&& client
->instance
== instance
)
759 /* This command is for debugging purpose. */
760 DEFUN (show_zebra_client
,
761 show_zebra_client_cmd
,
765 "Client information\n")
767 struct listnode
*node
;
768 struct zserv
*client
;
770 for (ALL_LIST_ELEMENTS_RO(zebrad
.client_list
, node
, client
))
771 zebra_show_client_detail(vty
, client
);
776 /* This command is for debugging purpose. */
777 DEFUN (show_zebra_client_summary
,
778 show_zebra_client_summary_cmd
,
779 "show zebra client summary",
782 "Client information brief\n"
785 struct listnode
*node
;
786 struct zserv
*client
;
789 "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes \n");
791 "--------------------------------------------------------------------------------\n");
793 for (ALL_LIST_ELEMENTS_RO(zebrad
.client_list
, node
, client
))
794 zebra_show_client_brief(vty
, client
);
796 vty_out(vty
, "Routes column shows (added+updated)/deleted\n");
800 #if defined(HANDLE_ZAPI_FUZZING)
801 void zserv_read_file(char *input
)
804 struct zserv
*client
= NULL
;
807 zebra_client_create(-1);
808 client
= zebrad
.client_list
->head
->data
;
811 fd
= open(input
, O_RDONLY
| O_NONBLOCK
);
814 zebra_client_read(&t
);
820 void zserv_init(void)
822 /* Client list init. */
823 zebrad
.client_list
= list_new();
824 zebrad
.client_list
->del
= (void (*)(void *))zebra_client_free
;
826 install_element(ENABLE_NODE
, &show_zebra_client_cmd
);
827 install_element(ENABLE_NODE
, &show_zebra_client_summary_cmd
);