]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zserv.c
zebra: cleanup for zapi_msg.c split
[mirror_frr.git] / zebra / zserv.c
1 /*
2 * Zebra API server.
3 * Portions:
4 * Copyright (C) 1997-1999 Kunihiro Ishiguro
5 * Copyright (C) 2015-2018 Cumulus Networks, Inc.
6 * et al.
7 *
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)
11 * any later version.
12 *
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
16 * more details.
17 *
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
21 */
22
23 #include <zebra.h>
24
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 */
35
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... */
55
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 */
61 /* clang-format on */
62
63 /* Event list of zebra. */
64 enum event { ZEBRA_READ, ZEBRA_WRITE };
65 /* privileges */
66 extern struct zebra_privs_t zserv_privs;
67 /* post event into client */
68 static void zebra_event(struct zserv *client, enum event event);
69
70
71 /* Public interface --------------------------------------------------------- */
72
73 int zebra_server_send_message(struct zserv *client, struct stream *msg)
74 {
75 stream_fifo_push(client->obuf_fifo, msg);
76 zebra_event(client, ZEBRA_WRITE);
77 return 0;
78 }
79
80 /* Lifecycle ---------------------------------------------------------------- */
81
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));
85
86 /* free zebra client information. */
87 static void zebra_client_free(struct zserv *client)
88 {
89 hook_call(zapi_client_close, client);
90
91 /* Close file descriptor. */
92 if (client->sock) {
93 unsigned long nroutes;
94
95 close(client->sock);
96 nroutes = rib_score_proto(client->proto, client->instance);
97 zlog_notice(
98 "client %d disconnected. %lu %s routes removed from the rib",
99 client->sock, nroutes,
100 zebra_route_string(client->proto));
101 client->sock = -1;
102 }
103
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);
113 if (client->wb)
114 buffer_free(client->wb);
115
116 /* Release threads. */
117 if (client->t_read)
118 thread_cancel(client->t_read);
119 if (client->t_write)
120 thread_cancel(client->t_write);
121 if (client->t_suicide)
122 thread_cancel(client->t_suicide);
123
124 /* Free bitmaps. */
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]);
128
129 vrf_bitmap_free(client->redist_default);
130 vrf_bitmap_free(client->ifinfo);
131 vrf_bitmap_free(client->ridinfo);
132
133 XFREE(MTYPE_TMP, client);
134 }
135
136 /*
137 * Called from client thread to terminate itself.
138 */
139 static void zebra_client_close(struct zserv *client)
140 {
141 listnode_delete(zebrad.client_list, client);
142 zebra_client_free(client);
143 }
144
145 /* Make new client. */
146 static void zebra_client_create(int sock)
147 {
148 struct zserv *client;
149 int i;
150 afi_t afi;
151
152 client = XCALLOC(MTYPE_TMP, sizeof(struct zserv));
153
154 /* Make client input/output buffer. */
155 client->sock = sock;
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);
161
162 /* Set table number. */
163 client->rtm_table = zebrad.rtm_table_default;
164
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();
173
174 /* by default, it's not a synchronous client */
175 client->is_synchronous = 0;
176
177 /* Add this client to linked list. */
178 listnode_add(zebrad.client_list, client);
179
180 zebra_vrf_update_all(client);
181
182 hook_call(zapi_client_connect, client);
183
184 /* start read loop */
185 zebra_event(client, ZEBRA_READ);
186 }
187
188 static int zserv_delayed_close(struct thread *thread)
189 {
190 struct zserv *client = THREAD_ARG(thread);
191
192 client->t_suicide = NULL;
193 zebra_client_close(client);
194 return 0;
195 }
196
197 /*
198 * Log zapi message to zlog.
199 *
200 * errmsg (optional)
201 * Debugging message
202 *
203 * msg
204 * The message
205 *
206 * hdr (optional)
207 * The message header
208 */
209 static void zserv_log_message(const char *errmsg, struct stream *msg,
210 struct zmsghdr *hdr)
211 {
212 zlog_debug("Rx'd ZAPI message");
213 if (errmsg)
214 zlog_debug("%s", errmsg);
215 if (hdr) {
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);
219 }
220 zlog_hexdump(msg->data, STREAM_READABLE(msg));
221 }
222
223 static int zserv_flush_data(struct thread *thread)
224 {
225 struct zserv *client = THREAD_ARG(thread);
226
227 client->t_write = NULL;
228 if (client->t_suicide) {
229 zebra_client_close(client);
230 return -1;
231 }
232 switch (buffer_flush_available(client->wb, client->sock)) {
233 case BUFFER_ERROR:
234 zlog_warn(
235 "%s: buffer_flush_available failed on zserv client fd %d, closing",
236 __func__, client->sock);
237 zebra_client_close(client);
238 client = NULL;
239 break;
240 case BUFFER_PENDING:
241 client->t_write = NULL;
242 thread_add_write(zebrad.master, zserv_flush_data, client,
243 client->sock, &client->t_write);
244 break;
245 case BUFFER_EMPTY:
246 break;
247 }
248
249 if (client)
250 client->last_write_time = monotime(NULL);
251 return 0;
252 }
253
254 /*
255 * Write a single packet.
256 */
257 static int zserv_write(struct thread *thread)
258 {
259 struct zserv *client = THREAD_ARG(thread);
260 struct stream *msg;
261 int writerv;
262
263 if (client->t_suicide)
264 return -1;
265
266 if (client->is_synchronous)
267 return 0;
268
269 msg = stream_fifo_pop(client->obuf_fifo);
270 stream_set_getp(msg, 0);
271 client->last_write_cmd = stream_getw_from(msg, 6);
272
273 writerv = buffer_write(client->wb, client->sock, STREAM_DATA(msg),
274 stream_get_endp(msg));
275
276 stream_free(msg);
277
278 switch (writerv) {
279 case BUFFER_ERROR:
280 zlog_warn(
281 "%s: buffer_write failed to zserv client fd %d, closing",
282 __func__, client->sock);
283 /*
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.
288 */
289 client->t_suicide = NULL;
290 thread_add_event(zebrad.master, zserv_delayed_close, client, 0,
291 &client->t_suicide);
292 return -1;
293 case BUFFER_EMPTY:
294 THREAD_OFF(client->t_write);
295 break;
296 case BUFFER_PENDING:
297 thread_add_write(zebrad.master, zserv_flush_data, client,
298 client->sock, &client->t_write);
299 break;
300 }
301
302 if (client->obuf_fifo->count)
303 zebra_event(client, ZEBRA_WRITE);
304
305 client->last_write_time = monotime(NULL);
306 return 0;
307 }
308
309 #if defined(HANDLE_ZAPI_FUZZING)
310 static void zserv_write_incoming(struct stream *orig, uint16_t command)
311 {
312 char fname[MAXPATHLEN];
313 struct stream *copy;
314 int fd = -1;
315
316 copy = stream_dup(orig);
317 stream_set_getp(copy, 0);
318
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);
323 close(fd);
324 zserv_privs.change(ZPRIVS_LOWER);
325 stream_free(copy);
326 }
327 #endif
328
329 static int zserv_process_messages(struct thread *thread)
330 {
331 struct zserv *client = THREAD_ARG(thread);
332 struct zebra_vrf *zvrf;
333 struct zmsghdr hdr;
334 struct stream *msg;
335 bool hdrvalid;
336
337 do {
338 msg = stream_fifo_pop(client->ibuf_fifo);
339
340 /* break if out of messages */
341 if (!msg)
342 continue;
343
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);
349 }
350 if (!hdrvalid)
351 continue;
352
353 hdr.length -= ZEBRA_HEADER_SIZE;
354 /* lookup vrf */
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);
359 }
360 if (!zvrf)
361 continue;
362
363 /* process commands */
364 zserv_handle_commands(client, &hdr, msg, zvrf);
365
366 } while (msg);
367
368 return 0;
369 }
370
371 /* Handler of zebra service request. */
372 static int zserv_read(struct thread *thread)
373 {
374 int sock;
375 struct zserv *client;
376 size_t already;
377 #if defined(HANDLE_ZAPI_FUZZING)
378 int packets = 1;
379 #else
380 int packets = zebrad.packets_to_process;
381 #endif
382 /* Get thread data. Reset reading thread because I'm running. */
383 sock = THREAD_FD(thread);
384 client = THREAD_ARG(thread);
385
386 if (client->t_suicide) {
387 zebra_client_close(client);
388 return -1;
389 }
390
391 while (packets) {
392 struct zmsghdr hdr;
393 ssize_t nb;
394 bool hdrvalid;
395 char errmsg[256];
396
397 already = stream_get_endp(client->ibuf_work);
398
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]",
405 sock);
406 if ((nb == 0 || nb == -1))
407 goto zread_fail;
408 if (nb != (ssize_t)(ZEBRA_HEADER_SIZE - already)) {
409 /* Try again later. */
410 break;
411 }
412 already = ZEBRA_HEADER_SIZE;
413 }
414
415 /* Reset to read from the beginning of the incoming packet. */
416 stream_set_getp(client->ibuf_work, 0);
417
418 /* Fetch header values */
419 hdrvalid = zapi_parse_header(client->ibuf_work, &hdr);
420
421 if (!hdrvalid) {
422 snprintf(errmsg, sizeof(errmsg),
423 "%s: Message has corrupt header", __func__);
424 zserv_log_message(errmsg, client->ibuf_work, NULL);
425 goto zread_fail;
426 }
427
428 /* Validate header */
429 if (hdr.marker != ZEBRA_HEADER_MARKER
430 || hdr.version != ZSERV_VERSION) {
431 snprintf(
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);
436 goto zread_fail;
437 }
438 if (hdr.length < ZEBRA_HEADER_SIZE) {
439 snprintf(
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);
444 goto zread_fail;
445 }
446 if (hdr.length > STREAM_SIZE(client->ibuf_work)) {
447 snprintf(
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));
452 goto zread_fail;
453 }
454
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)
460 zlog_debug(
461 "connection closed [%d] when reading zebra data",
462 sock);
463 if ((nb == 0 || nb == -1))
464 goto zread_fail;
465 if (nb != (ssize_t)(hdr.length - already)) {
466 /* Try again later. */
467 break;
468 }
469 }
470
471 #if defined(HANDLE_ZAPI_FUZZING)
472 zserv_write_incoming(client->ibuf_work, command);
473 #endif
474
475 /* Debug packet information. */
476 if (IS_ZEBRA_DEBUG_EVENT)
477 zlog_debug("zebra message comes from socket [%d]",
478 sock);
479
480 if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
481 zserv_log_message(NULL, client->ibuf_work, &hdr);
482
483 client->last_read_time = monotime(NULL);
484 client->last_read_cmd = hdr.command;
485
486 stream_set_getp(client->ibuf_work, 0);
487 struct stream *msg = stream_dup(client->ibuf_work);
488
489 stream_fifo_push(client->ibuf_fifo, msg);
490
491 if (client->t_suicide)
492 goto zread_fail;
493
494 --packets;
495 stream_reset(client->ibuf_work);
496 }
497
498 if (IS_ZEBRA_DEBUG_PACKET)
499 zlog_debug("Read %d packets",
500 zebrad.packets_to_process - packets);
501
502 /* Schedule job to process those packets */
503 thread_add_event(zebrad.master, &zserv_process_messages, client, 0,
504 NULL);
505
506 /* Reschedule ourselves */
507 zebra_event(client, ZEBRA_READ);
508
509 return 0;
510
511 zread_fail:
512 zebra_client_close(client);
513 return -1;
514 }
515
516 static void zebra_event(struct zserv *client, enum event event)
517 {
518 switch (event) {
519 case ZEBRA_READ:
520 thread_add_read(zebrad.master, zserv_read, client, client->sock,
521 &client->t_read);
522 break;
523 case ZEBRA_WRITE:
524 thread_add_write(zebrad.master, zserv_write, client,
525 client->sock, &client->t_write);
526 break;
527 }
528 }
529
530 /* Accept code of zebra server socket. */
531 static int zebra_accept(struct thread *thread)
532 {
533 int accept_sock;
534 int client_sock;
535 struct sockaddr_in client;
536 socklen_t len;
537
538 accept_sock = THREAD_FD(thread);
539
540 /* Reregister myself. */
541 thread_add_read(zebrad.master, zebra_accept, NULL, accept_sock, NULL);
542
543 len = sizeof(struct sockaddr_in);
544 client_sock = accept(accept_sock, (struct sockaddr *)&client, &len);
545
546 if (client_sock < 0) {
547 zlog_warn("Can't accept zebra socket: %s",
548 safe_strerror(errno));
549 return -1;
550 }
551
552 /* Make client socket non-blocking. */
553 set_nonblocking(client_sock);
554
555 /* Create new zebra client. */
556 zebra_client_create(client_sock);
557
558 return 0;
559 }
560
561 /* Make zebra server socket, wiping any existing one (see bug #403). */
562 void zebra_zserv_socket_init(char *path)
563 {
564 int ret;
565 int sock;
566 mode_t old_mask;
567 struct sockaddr_storage sa;
568 socklen_t sa_len;
569
570 if (!frr_zclient_addr(&sa, &sa_len, path))
571 /* should be caught in zebra main() */
572 return;
573
574 /* Set umask */
575 old_mask = umask(0077);
576
577 /* Make UNIX domain socket. */
578 sock = socket(sa.ss_family, SOCK_STREAM, 0);
579 if (sock < 0) {
580 zlog_warn("Can't create zserv socket: %s",
581 safe_strerror(errno));
582 zlog_warn(
583 "zebra can't provide full functionality due to above error");
584 return;
585 }
586
587 if (sa.ss_family != AF_UNIX) {
588 sockopt_reuseaddr(sock);
589 sockopt_reuseport(sock);
590 } else {
591 struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
592 if (suna->sun_path[0])
593 unlink(suna->sun_path);
594 }
595
596 zserv_privs.change(ZPRIVS_RAISE);
597 setsockopt_so_recvbuf(sock, 1048576);
598 setsockopt_so_sendbuf(sock, 1048576);
599 zserv_privs.change(ZPRIVS_LOWER);
600
601 if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_RAISE))
602 zlog_err("Can't raise privileges");
603
604 ret = bind(sock, (struct sockaddr *)&sa, sa_len);
605 if (ret < 0) {
606 zlog_warn("Can't bind zserv socket on %s: %s", path,
607 safe_strerror(errno));
608 zlog_warn(
609 "zebra can't provide full functionality due to above error");
610 close(sock);
611 return;
612 }
613 if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_LOWER))
614 zlog_err("Can't lower privileges");
615
616 ret = listen(sock, 5);
617 if (ret < 0) {
618 zlog_warn("Can't listen to zserv socket %s: %s", path,
619 safe_strerror(errno));
620 zlog_warn(
621 "zebra can't provide full functionality due to above error");
622 close(sock);
623 return;
624 }
625
626 umask(old_mask);
627
628 thread_add_read(zebrad.master, zebra_accept, NULL, sock, NULL);
629 }
630
631 #define ZEBRA_TIME_BUF 32
632 static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
633 {
634 struct tm *tm;
635 time_t now;
636
637 assert(buf != NULL);
638 assert(buflen >= ZEBRA_TIME_BUF);
639 assert(time1 != NULL);
640
641 if (!*time1) {
642 snprintf(buf, buflen, "never ");
643 return (buf);
644 }
645
646 now = monotime(NULL);
647 now -= *time1;
648 tm = gmtime(&now);
649
650 if (now < ONE_DAY_SECOND)
651 snprintf(buf, buflen, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
652 tm->tm_sec);
653 else if (now < ONE_WEEK_SECOND)
654 snprintf(buf, buflen, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
655 tm->tm_min);
656 else
657 snprintf(buf, buflen, "%02dw%dd%02dh", tm->tm_yday / 7,
658 tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
659 return buf;
660 }
661
662 static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
663 {
664 char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
665 char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
666
667 vty_out(vty, "Client: %s", zebra_route_string(client->proto));
668 if (client->instance)
669 vty_out(vty, " Instance: %d", client->instance);
670 vty_out(vty, "\n");
671
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);
675
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,
681 ZEBRA_TIME_BUF));
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,
685 ZEBRA_TIME_BUF));
686 else
687 vty_out(vty, "No Nexthop Update sent\n");
688 } else
689 vty_out(vty, "Not registered for Nexthop Updates\n");
690
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));
701 vty_out(vty, "\n");
702
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,
714 client->ifdel_cnt);
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);
725
726 vty_out(vty, "\n");
727 return;
728 }
729
730 static void zebra_show_client_brief(struct vty *vty, struct zserv *client)
731 {
732 char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
733 char wbuf[ZEBRA_TIME_BUF];
734
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);
744 }
745
746 struct zserv *zebra_find_client(uint8_t proto, unsigned short instance)
747 {
748 struct listnode *node, *nnode;
749 struct zserv *client;
750
751 for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
752 if (client->proto == proto && client->instance == instance)
753 return client;
754 }
755
756 return NULL;
757 }
758
759 /* This command is for debugging purpose. */
760 DEFUN (show_zebra_client,
761 show_zebra_client_cmd,
762 "show zebra client",
763 SHOW_STR
764 ZEBRA_STR
765 "Client information\n")
766 {
767 struct listnode *node;
768 struct zserv *client;
769
770 for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
771 zebra_show_client_detail(vty, client);
772
773 return CMD_SUCCESS;
774 }
775
776 /* This command is for debugging purpose. */
777 DEFUN (show_zebra_client_summary,
778 show_zebra_client_summary_cmd,
779 "show zebra client summary",
780 SHOW_STR
781 ZEBRA_STR
782 "Client information brief\n"
783 "Brief Summary\n")
784 {
785 struct listnode *node;
786 struct zserv *client;
787
788 vty_out(vty,
789 "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes \n");
790 vty_out(vty,
791 "--------------------------------------------------------------------------------\n");
792
793 for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
794 zebra_show_client_brief(vty, client);
795
796 vty_out(vty, "Routes column shows (added+updated)/deleted\n");
797 return CMD_SUCCESS;
798 }
799
800 #if defined(HANDLE_ZAPI_FUZZING)
801 void zserv_read_file(char *input)
802 {
803 int fd;
804 struct zserv *client = NULL;
805 struct thread t;
806
807 zebra_client_create(-1);
808 client = zebrad.client_list->head->data;
809 t.arg = client;
810
811 fd = open(input, O_RDONLY | O_NONBLOCK);
812 t.u.fd = fd;
813
814 zebra_client_read(&t);
815
816 close(fd);
817 }
818 #endif
819
820 void zserv_init(void)
821 {
822 /* Client list init. */
823 zebrad.client_list = list_new();
824 zebrad.client_list->del = (void (*)(void *))zebra_client_free;
825
826 install_element(ENABLE_NODE, &show_zebra_client_cmd);
827 install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
828 }