Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Zebra API server.
4 : * Portions:
5 : * Copyright (C) 1997-1999 Kunihiro Ishiguro
6 : * Copyright (C) 2015-2018 Cumulus Networks, Inc.
7 : * et al.
8 : */
9 :
10 : #include <zebra.h>
11 :
12 : /* clang-format off */
13 : #include <errno.h> /* for errno */
14 : #include <netinet/in.h> /* for sockaddr_in */
15 : #include <stdint.h> /* for uint8_t */
16 : #include <stdio.h> /* for snprintf */
17 : #include <sys/socket.h> /* for sockaddr_storage, AF_UNIX, accept... */
18 : #include <sys/stat.h> /* for umask, mode_t */
19 : #include <sys/un.h> /* for sockaddr_un */
20 : #include <time.h> /* for NULL, tm, gmtime, time_t */
21 : #include <unistd.h> /* for close, unlink, ssize_t */
22 :
23 : #include "lib/buffer.h" /* for BUFFER_EMPTY, BUFFER_ERROR, BUFFE... */
24 : #include "lib/command.h" /* for vty, install_element, CMD_SUCCESS... */
25 : #include "lib/hook.h" /* for DEFINE_HOOK, DEFINE_KOOH, hook_call */
26 : #include "lib/linklist.h" /* for ALL_LIST_ELEMENTS_RO, ALL_LIST_EL... */
27 : #include "lib/libfrr.h" /* for frr_zclient_addr */
28 : #include "lib/log.h" /* for zlog_warn, zlog_debug, safe_strerror */
29 : #include "lib/memory.h" /* for MTYPE_TMP, XCALLOC, XFREE */
30 : #include "lib/monotime.h" /* for monotime, ONE_DAY_SECOND, ONE_WEE... */
31 : #include "lib/network.h" /* for set_nonblocking */
32 : #include "lib/privs.h" /* for zebra_privs_t, ZPRIVS_LOWER, ZPRI... */
33 : #include "lib/route_types.h" /* for ZEBRA_ROUTE_MAX */
34 : #include "lib/sockopt.h" /* for setsockopt_so_recvbuf, setsockopt... */
35 : #include "lib/sockunion.h" /* for sockopt_reuseaddr, sockopt_reuseport */
36 : #include "lib/stream.h" /* for STREAM_SIZE, stream (ptr only), ... */
37 : #include "frrevent.h" /* for thread (ptr only), EVENT_ARG, ... */
38 : #include "lib/vrf.h" /* for vrf_info_lookup, VRF_DEFAULT */
39 : #include "lib/vty.h" /* for vty_out, vty (ptr only) */
40 : #include "lib/zclient.h" /* for zmsghdr, ZEBRA_HEADER_SIZE, ZEBRA... */
41 : #include "lib/frr_pthread.h" /* for frr_pthread_new, frr_pthread_stop... */
42 : #include "lib/frratomic.h" /* for atomic_load_explicit, atomic_stor... */
43 : #include "lib/lib_errors.h" /* for generic ferr ids */
44 : #include "lib/printfrr.h" /* for string functions */
45 :
46 : #include "zebra/debug.h" /* for various debugging macros */
47 : #include "zebra/rib.h" /* for rib_score_proto */
48 : #include "zebra/zapi_msg.h" /* for zserv_handle_commands */
49 : #include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */
50 : #include "zebra/zserv.h" /* for zserv */
51 : #include "zebra/zebra_router.h"
52 : #include "zebra/zebra_errors.h" /* for error messages */
53 : /* clang-format on */
54 :
55 : /* privileges */
56 : extern struct zebra_privs_t zserv_privs;
57 :
58 : /* The listener socket for clients connecting to us */
59 : static int zsock;
60 :
61 : /* The lock that protects access to zapi client objects */
62 : static pthread_mutex_t client_mutex;
63 :
64 : static struct zserv *find_client_internal(uint8_t proto,
65 : unsigned short instance,
66 : uint32_t session_id);
67 :
68 : /* Mem type for zclients. */
69 6 : DEFINE_MTYPE_STATIC(ZEBRA, ZSERV_CLIENT, "ZClients");
70 :
71 : /*
72 : * Client thread events.
73 : *
74 : * These are used almost exclusively by client threads to drive their own event
75 : * loops. The only exception is in zserv_client_create(), which pushes an
76 : * initial ZSERV_CLIENT_READ event to start the API handler loop.
77 : */
78 : enum zserv_client_event {
79 : /* Schedule a socket read */
80 : ZSERV_CLIENT_READ,
81 : /* Schedule a buffer write */
82 : ZSERV_CLIENT_WRITE,
83 : };
84 :
85 : /*
86 : * Main thread events.
87 : *
88 : * These are used by client threads to notify the main thread about various
89 : * events and to make processing requests.
90 : */
91 : enum zserv_event {
92 : /* Schedule listen job on Zebra API socket */
93 : ZSERV_ACCEPT,
94 : /* The calling client has packets on its input buffer */
95 : ZSERV_PROCESS_MESSAGES,
96 : /* The calling client wishes to be killed */
97 : ZSERV_HANDLE_CLIENT_FAIL,
98 : };
99 :
100 : /*
101 : * Zebra server event driver for all client threads.
102 : *
103 : * This is essentially a wrapper around event_add_event() that centralizes
104 : * those scheduling calls into one place.
105 : *
106 : * All calls to this function schedule an event on the pthread running the
107 : * provided client.
108 : *
109 : * client
110 : * the client in question, and thread target
111 : *
112 : * event
113 : * the event to notify them about
114 : */
115 : static void zserv_client_event(struct zserv *client,
116 : enum zserv_client_event event);
117 :
118 : /*
119 : * Zebra server event driver for the main thread.
120 : *
121 : * This is essentially a wrapper around event_add_event() that centralizes
122 : * those scheduling calls into one place.
123 : *
124 : * All calls to this function schedule an event on Zebra's main pthread.
125 : *
126 : * client
127 : * the client in question
128 : *
129 : * event
130 : * the event to notify the main thread about
131 : */
132 : static void zserv_event(struct zserv *client, enum zserv_event event);
133 :
134 :
135 : /* Client thread lifecycle -------------------------------------------------- */
136 :
137 : /*
138 : * Free a zserv client object.
139 : */
140 6 : void zserv_client_delete(struct zserv *client)
141 : {
142 0 : XFREE(MTYPE_ZSERV_CLIENT, client);
143 6 : }
144 :
145 : /*
146 : * Log zapi message to zlog.
147 : *
148 : * errmsg (optional)
149 : * Debugging message
150 : *
151 : * msg
152 : * The message
153 : *
154 : * hdr (optional)
155 : * The message header
156 : */
157 0 : void zserv_log_message(const char *errmsg, struct stream *msg,
158 : struct zmsghdr *hdr)
159 : {
160 0 : zlog_debug("Rx'd ZAPI message");
161 0 : if (errmsg)
162 0 : zlog_debug("%s", errmsg);
163 0 : if (hdr) {
164 0 : zlog_debug(" Length: %d", hdr->length);
165 0 : zlog_debug("Command: %s", zserv_command_string(hdr->command));
166 0 : zlog_debug(" VRF: %u", hdr->vrf_id);
167 : }
168 0 : stream_hexdump(msg);
169 0 : }
170 :
171 : /*
172 : * Gracefuly shut down a client connection.
173 : *
174 : * Cancel any pending tasks for the client's thread. Then schedule a task on
175 : * the main thread to shut down the calling thread.
176 : *
177 : * It is not safe to close the client socket in this function. The socket is
178 : * owned by the main thread.
179 : *
180 : * Must be called from the client pthread, never the main thread.
181 : */
182 6 : static void zserv_client_fail(struct zserv *client)
183 : {
184 6 : flog_warn(
185 : EC_ZEBRA_CLIENT_IO_ERROR,
186 : "Client '%s' (session id %d) encountered an error and is shutting down.",
187 : zebra_route_string(client->proto), client->session_id);
188 :
189 6 : atomic_store_explicit(&client->pthread->running, false,
190 : memory_order_relaxed);
191 :
192 6 : EVENT_OFF(client->t_read);
193 6 : EVENT_OFF(client->t_write);
194 6 : zserv_event(client, ZSERV_HANDLE_CLIENT_FAIL);
195 6 : }
196 :
197 : /*
198 : * Write all pending messages to client socket.
199 : *
200 : * This function first attempts to flush any buffered data. If unsuccessful,
201 : * the function reschedules itself and returns. If successful, it pops all
202 : * available messages from the output queue and continues to write data
203 : * directly to the socket until the socket would block. If the socket never
204 : * blocks and all data is written, the function returns without rescheduling
205 : * itself. If the socket ends up throwing EWOULDBLOCK, the remaining data is
206 : * buffered and the function reschedules itself.
207 : *
208 : * The utility of the buffer is that it allows us to vastly reduce lock
209 : * contention by allowing us to pop *all* messages off the output queue at once
210 : * instead of locking and unlocking each time we want to pop a single message
211 : * off the queue. The same thing could arguably be accomplished faster by
212 : * allowing the main thread to write directly into the buffer instead of
213 : * enqueuing packets onto an intermediary queue, but the intermediary queue
214 : * allows us to expose information about input and output queues to the user in
215 : * terms of number of packets rather than size of data.
216 : */
217 42 : static void zserv_write(struct event *thread)
218 : {
219 42 : struct zserv *client = EVENT_ARG(thread);
220 42 : struct stream *msg;
221 42 : uint32_t wcmd = 0;
222 42 : struct stream_fifo *cache;
223 42 : uint64_t time_now = monotime(NULL);
224 :
225 : /* If we have any data pending, try to flush it first */
226 42 : switch (buffer_flush_all(client->wb, client->sock)) {
227 0 : case BUFFER_ERROR:
228 0 : goto zwrite_fail;
229 0 : case BUFFER_PENDING:
230 0 : frr_with_mutex (&client->stats_mtx) {
231 0 : client->last_write_time = time_now;
232 : }
233 0 : zserv_client_event(client, ZSERV_CLIENT_WRITE);
234 0 : return;
235 : case BUFFER_EMPTY:
236 : break;
237 : }
238 :
239 42 : cache = stream_fifo_new();
240 :
241 84 : frr_with_mutex (&client->obuf_mtx) {
242 209 : while (stream_fifo_head(client->obuf_fifo))
243 167 : stream_fifo_push(cache,
244 : stream_fifo_pop(client->obuf_fifo));
245 : }
246 :
247 42 : if (cache->tail) {
248 42 : msg = cache->tail;
249 42 : stream_set_getp(msg, 0);
250 42 : wcmd = stream_getw_from(msg, ZAPI_HEADER_CMD_LOCATION);
251 : }
252 :
253 209 : while (stream_fifo_head(cache)) {
254 167 : msg = stream_fifo_pop(cache);
255 167 : buffer_put(client->wb, STREAM_DATA(msg), stream_get_endp(msg));
256 167 : stream_free(msg);
257 : }
258 :
259 42 : stream_fifo_free(cache);
260 :
261 : /* If we have any data pending, try to flush it first */
262 42 : switch (buffer_flush_all(client->wb, client->sock)) {
263 0 : case BUFFER_ERROR:
264 0 : goto zwrite_fail;
265 0 : case BUFFER_PENDING:
266 0 : frr_with_mutex (&client->stats_mtx) {
267 0 : client->last_write_time = time_now;
268 : }
269 0 : zserv_client_event(client, ZSERV_CLIENT_WRITE);
270 0 : return;
271 : case BUFFER_EMPTY:
272 : break;
273 : }
274 :
275 42 : frr_with_mutex (&client->stats_mtx) {
276 42 : client->last_write_cmd = wcmd;
277 42 : client->last_write_time = time_now;
278 : }
279 42 : return;
280 :
281 0 : zwrite_fail:
282 0 : flog_warn(EC_ZEBRA_CLIENT_WRITE_FAILED,
283 : "%s: could not write to %s [fd = %d], closing.", __func__,
284 : zebra_route_string(client->proto), client->sock);
285 0 : zserv_client_fail(client);
286 : }
287 :
288 : /*
289 : * Read and process data from a client socket.
290 : *
291 : * The responsibilities here are to read raw data from the client socket,
292 : * validate the header, encapsulate it into a single stream object, push it
293 : * onto the input queue and then notify the main thread that there is new data
294 : * available.
295 : *
296 : * This function first looks for any data in the client structure's working
297 : * input buffer. If data is present, it is assumed that reading stopped in a
298 : * previous invocation of this task and needs to be resumed to finish a message.
299 : * Otherwise, the socket data stream is assumed to be at the beginning of a new
300 : * ZAPI message (specifically at the header). The header is read and validated.
301 : * If the header passed validation then the length field found in the header is
302 : * used to compute the total length of the message. That much data is read (but
303 : * not inspected), appended to the header, placed into a stream and pushed onto
304 : * the client's input queue. A task is then scheduled on the main thread to
305 : * process the client's input queue. Finally, if all of this was successful,
306 : * this task reschedules itself.
307 : *
308 : * Any failure in any of these actions is handled by terminating the client.
309 : */
310 38 : static void zserv_read(struct event *thread)
311 : {
312 38 : struct zserv *client = EVENT_ARG(thread);
313 38 : int sock;
314 38 : size_t already;
315 38 : struct stream_fifo *cache;
316 38 : uint32_t p2p_orig;
317 :
318 38 : uint32_t p2p;
319 38 : struct zmsghdr hdr;
320 :
321 38 : p2p_orig = atomic_load_explicit(&zrouter.packets_to_process,
322 : memory_order_relaxed);
323 38 : cache = stream_fifo_new();
324 38 : p2p = p2p_orig;
325 38 : sock = EVENT_FD(thread);
326 :
327 170 : while (p2p) {
328 170 : ssize_t nb;
329 170 : bool hdrvalid;
330 170 : char errmsg[256];
331 :
332 170 : already = stream_get_endp(client->ibuf_work);
333 :
334 : /* Read length and command (if we don't have it already). */
335 170 : if (already < ZEBRA_HEADER_SIZE) {
336 170 : nb = stream_read_try(client->ibuf_work, sock,
337 : ZEBRA_HEADER_SIZE - already);
338 170 : if ((nb == 0 || nb == -1)) {
339 6 : if (IS_ZEBRA_DEBUG_EVENT)
340 0 : zlog_debug("connection closed socket [%d]",
341 : sock);
342 6 : goto zread_fail;
343 : }
344 164 : if (nb != (ssize_t)(ZEBRA_HEADER_SIZE - already)) {
345 : /* Try again later. */
346 : break;
347 : }
348 : already = ZEBRA_HEADER_SIZE;
349 : }
350 :
351 : /* Reset to read from the beginning of the incoming packet. */
352 132 : stream_set_getp(client->ibuf_work, 0);
353 :
354 : /* Fetch header values */
355 132 : hdrvalid = zapi_parse_header(client->ibuf_work, &hdr);
356 :
357 132 : if (!hdrvalid) {
358 0 : snprintf(errmsg, sizeof(errmsg),
359 : "%s: Message has corrupt header", __func__);
360 0 : zserv_log_message(errmsg, client->ibuf_work, NULL);
361 0 : goto zread_fail;
362 : }
363 :
364 : /* Validate header */
365 132 : if (hdr.marker != ZEBRA_HEADER_MARKER
366 132 : || hdr.version != ZSERV_VERSION) {
367 0 : snprintf(
368 : errmsg, sizeof(errmsg),
369 : "Message has corrupt header\n%s: socket %d version mismatch, marker %d, version %d",
370 0 : __func__, sock, hdr.marker, hdr.version);
371 0 : zserv_log_message(errmsg, client->ibuf_work, &hdr);
372 0 : goto zread_fail;
373 : }
374 132 : if (hdr.length < ZEBRA_HEADER_SIZE) {
375 0 : snprintf(
376 : errmsg, sizeof(errmsg),
377 : "Message has corrupt header\n%s: socket %d message length %u is less than header size %d",
378 : __func__, sock, hdr.length, ZEBRA_HEADER_SIZE);
379 0 : zserv_log_message(errmsg, client->ibuf_work, &hdr);
380 0 : goto zread_fail;
381 : }
382 132 : if (hdr.length > STREAM_SIZE(client->ibuf_work)) {
383 0 : snprintf(
384 : errmsg, sizeof(errmsg),
385 : "Message has corrupt header\n%s: socket %d message length %u exceeds buffer size %lu",
386 : __func__, sock, hdr.length,
387 : (unsigned long)STREAM_SIZE(client->ibuf_work));
388 0 : zserv_log_message(errmsg, client->ibuf_work, &hdr);
389 0 : goto zread_fail;
390 : }
391 :
392 : /* Read rest of data. */
393 132 : if (already < hdr.length) {
394 124 : nb = stream_read_try(client->ibuf_work, sock,
395 : hdr.length - already);
396 124 : if ((nb == 0 || nb == -1)) {
397 0 : if (IS_ZEBRA_DEBUG_EVENT)
398 0 : zlog_debug(
399 : "connection closed [%d] when reading zebra data",
400 : sock);
401 0 : goto zread_fail;
402 : }
403 124 : if (nb != (ssize_t)(hdr.length - already)) {
404 : /* Try again later. */
405 : break;
406 : }
407 : }
408 :
409 : /* Debug packet information. */
410 132 : if (IS_ZEBRA_DEBUG_PACKET)
411 0 : zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]",
412 : zserv_command_string(hdr.command),
413 : hdr.vrf_id, hdr.length,
414 : sock);
415 :
416 132 : stream_set_getp(client->ibuf_work, 0);
417 132 : struct stream *msg = stream_dup(client->ibuf_work);
418 :
419 132 : stream_fifo_push(cache, msg);
420 132 : stream_reset(client->ibuf_work);
421 132 : p2p--;
422 : }
423 :
424 32 : if (p2p < p2p_orig) {
425 32 : uint64_t time_now = monotime(NULL);
426 :
427 : /* update session statistics */
428 32 : frr_with_mutex (&client->stats_mtx) {
429 32 : client->last_read_time = time_now;
430 32 : client->last_read_cmd = hdr.command;
431 : }
432 :
433 : /* publish read packets on client's input queue */
434 64 : frr_with_mutex (&client->ibuf_mtx) {
435 164 : while (cache->head)
436 132 : stream_fifo_push(client->ibuf_fifo,
437 : stream_fifo_pop(cache));
438 : }
439 :
440 : /* Schedule job to process those packets */
441 32 : zserv_event(client, ZSERV_PROCESS_MESSAGES);
442 :
443 : }
444 :
445 32 : if (IS_ZEBRA_DEBUG_PACKET)
446 0 : zlog_debug("Read %d packets from client: %s", p2p_orig - p2p,
447 : zebra_route_string(client->proto));
448 :
449 : /* Reschedule ourselves */
450 32 : zserv_client_event(client, ZSERV_CLIENT_READ);
451 :
452 32 : stream_fifo_free(cache);
453 :
454 32 : return;
455 :
456 6 : zread_fail:
457 6 : stream_fifo_free(cache);
458 6 : zserv_client_fail(client);
459 : }
460 :
461 209 : static void zserv_client_event(struct zserv *client,
462 : enum zserv_client_event event)
463 : {
464 209 : switch (event) {
465 38 : case ZSERV_CLIENT_READ:
466 38 : event_add_read(client->pthread->master, zserv_read, client,
467 : client->sock, &client->t_read);
468 38 : break;
469 171 : case ZSERV_CLIENT_WRITE:
470 171 : event_add_write(client->pthread->master, zserv_write, client,
471 : client->sock, &client->t_write);
472 171 : break;
473 : }
474 209 : }
475 :
476 : /* Main thread lifecycle ---------------------------------------------------- */
477 :
478 : /*
479 : * Read and process messages from a client.
480 : *
481 : * This task runs on the main pthread. It is scheduled by client pthreads when
482 : * they have new messages available on their input queues. The client is passed
483 : * as the task argument.
484 : *
485 : * Each message is popped off the client's input queue and the action associated
486 : * with the message is executed. This proceeds until there are no more messages,
487 : * an error occurs, or the processing limit is reached.
488 : *
489 : * The client's I/O thread can push at most zrouter.packets_to_process messages
490 : * onto the input buffer before notifying us there are packets to read. As long
491 : * as we always process zrouter.packets_to_process messages here, then we can
492 : * rely on the read thread to handle queuing this task enough times to process
493 : * everything on the input queue.
494 : */
495 30 : static void zserv_process_messages(struct event *thread)
496 : {
497 30 : struct zserv *client = EVENT_ARG(thread);
498 30 : struct stream *msg;
499 30 : struct stream_fifo *cache = stream_fifo_new();
500 30 : uint32_t p2p = zrouter.packets_to_process;
501 30 : bool need_resched = false;
502 :
503 60 : frr_with_mutex (&client->ibuf_mtx) {
504 : uint32_t i;
505 162 : for (i = 0; i < p2p && stream_fifo_head(client->ibuf_fifo);
506 132 : ++i) {
507 132 : msg = stream_fifo_pop(client->ibuf_fifo);
508 132 : stream_fifo_push(cache, msg);
509 : }
510 :
511 : /* Need to reschedule processing work if there are still
512 : * packets in the fifo.
513 : */
514 30 : if (stream_fifo_head(client->ibuf_fifo))
515 0 : need_resched = true;
516 : }
517 :
518 : /* Process the batch of messages */
519 30 : if (stream_fifo_head(cache))
520 30 : zserv_handle_commands(client, cache);
521 :
522 30 : stream_fifo_free(cache);
523 :
524 : /* Reschedule ourselves if necessary */
525 30 : if (need_resched)
526 0 : zserv_event(client, ZSERV_PROCESS_MESSAGES);
527 30 : }
528 :
529 171 : int zserv_send_message(struct zserv *client, struct stream *msg)
530 : {
531 342 : frr_with_mutex (&client->obuf_mtx) {
532 171 : stream_fifo_push(client->obuf_fifo, msg);
533 : }
534 :
535 171 : zserv_client_event(client, ZSERV_CLIENT_WRITE);
536 :
537 171 : return 0;
538 : }
539 :
540 : /*
541 : * Send a batch of messages to a connected Zebra API client.
542 : */
543 0 : int zserv_send_batch(struct zserv *client, struct stream_fifo *fifo)
544 : {
545 0 : struct stream *msg;
546 :
547 0 : frr_with_mutex (&client->obuf_mtx) {
548 0 : msg = stream_fifo_pop(fifo);
549 0 : while (msg) {
550 0 : stream_fifo_push(client->obuf_fifo, msg);
551 0 : msg = stream_fifo_pop(fifo);
552 : }
553 : }
554 :
555 0 : zserv_client_event(client, ZSERV_CLIENT_WRITE);
556 :
557 0 : return 0;
558 : }
559 :
560 : /* Hooks for client connect / disconnect */
561 6 : DEFINE_HOOK(zserv_client_connect, (struct zserv *client), (client));
562 66 : DEFINE_KOOH(zserv_client_close, (struct zserv *client), (client));
563 :
564 : /*
565 : * Deinitialize zebra client.
566 : *
567 : * - Deregister and deinitialize related internal resources
568 : * - Gracefuly close socket
569 : * - Free associated resources
570 : * - Free client structure
571 : *
572 : * This does *not* take any action on the struct event * fields. These are
573 : * managed by the owning pthread and any tasks associated with them must have
574 : * been stopped prior to invoking this function.
575 : */
576 6 : static void zserv_client_free(struct zserv *client)
577 : {
578 6 : if (client == NULL)
579 : return;
580 :
581 6 : hook_call(zserv_client_close, client);
582 :
583 : /* Close file descriptor. */
584 6 : if (client->sock) {
585 6 : unsigned long nroutes = 0;
586 6 : unsigned long nnhgs = 0;
587 :
588 6 : close(client->sock);
589 :
590 6 : if (DYNAMIC_CLIENT_GR_DISABLED(client)) {
591 6 : if (!client->synchronous) {
592 4 : zebra_mpls_client_cleanup_vrf_label(
593 : client->proto);
594 :
595 4 : nroutes = rib_score_proto(client->proto,
596 4 : client->instance);
597 : }
598 6 : zlog_notice(
599 : "client %d disconnected %lu %s routes removed from the rib",
600 : client->sock, nroutes,
601 : zebra_route_string(client->proto));
602 :
603 : /* Not worrying about instance for now */
604 6 : if (!client->synchronous)
605 4 : nnhgs = zebra_nhg_score_proto(client->proto);
606 6 : zlog_notice(
607 : "client %d disconnected %lu %s nhgs removed from the rib",
608 : client->sock, nnhgs,
609 : zebra_route_string(client->proto));
610 : }
611 6 : client->sock = -1;
612 : }
613 :
614 : /* Free stream buffers. */
615 6 : if (client->ibuf_work)
616 6 : stream_free(client->ibuf_work);
617 6 : if (client->obuf_work)
618 6 : stream_free(client->obuf_work);
619 6 : if (client->ibuf_fifo)
620 6 : stream_fifo_free(client->ibuf_fifo);
621 6 : if (client->obuf_fifo)
622 6 : stream_fifo_free(client->obuf_fifo);
623 6 : if (client->wb)
624 6 : buffer_free(client->wb);
625 :
626 : /* Free buffer mutexes */
627 6 : pthread_mutex_destroy(&client->stats_mtx);
628 6 : pthread_mutex_destroy(&client->obuf_mtx);
629 6 : pthread_mutex_destroy(&client->ibuf_mtx);
630 :
631 : /* Free bitmaps. */
632 24 : for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
633 594 : for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
634 576 : vrf_bitmap_free(&client->redist[afi][i]);
635 576 : redist_del_all_instances(&client->mi_redist[afi][i]);
636 : }
637 :
638 18 : vrf_bitmap_free(&client->redist_default[afi]);
639 18 : vrf_bitmap_free(&client->ridinfo[afi]);
640 18 : vrf_bitmap_free(&client->nhrp_neighinfo[afi]);
641 : }
642 :
643 : /*
644 : * If any instance are graceful restart enabled,
645 : * client is not deleted
646 : */
647 6 : if (DYNAMIC_CLIENT_GR_DISABLED(client)) {
648 6 : if (IS_ZEBRA_DEBUG_EVENT)
649 0 : zlog_debug("%s: Deleting client %s", __func__,
650 : zebra_route_string(client->proto));
651 6 : zserv_client_delete(client);
652 : } else {
653 : /* Handle cases where client has GR instance. */
654 0 : if (IS_ZEBRA_DEBUG_EVENT)
655 0 : zlog_debug("%s: client %s restart enabled", __func__,
656 : zebra_route_string(client->proto));
657 0 : if (zebra_gr_client_disconnect(client) < 0)
658 0 : zlog_err(
659 : "%s: GR enabled but could not handle disconnect event",
660 : __func__);
661 : }
662 : }
663 :
664 6 : void zserv_close_client(struct zserv *client)
665 : {
666 6 : bool free_p = true;
667 :
668 6 : if (client->pthread) {
669 : /* synchronously stop and join pthread */
670 6 : frr_pthread_stop(client->pthread, NULL);
671 :
672 6 : if (IS_ZEBRA_DEBUG_EVENT)
673 0 : zlog_debug("Closing client '%s'",
674 : zebra_route_string(client->proto));
675 :
676 6 : event_cancel_event(zrouter.master, client);
677 6 : EVENT_OFF(client->t_cleanup);
678 6 : EVENT_OFF(client->t_process);
679 :
680 : /* destroy pthread */
681 6 : frr_pthread_destroy(client->pthread);
682 6 : client->pthread = NULL;
683 : }
684 :
685 : /*
686 : * Final check in case the client struct is in use in another
687 : * pthread: if not in-use, continue and free the client
688 : */
689 12 : frr_with_mutex (&client_mutex) {
690 6 : if (client->busy_count <= 0) {
691 : /* remove from client list */
692 6 : listnode_delete(zrouter.client_list, client);
693 : } else {
694 : /*
695 : * The client session object may be in use, although
696 : * the associated pthread is gone. Defer final
697 : * cleanup.
698 : */
699 0 : client->is_closed = true;
700 0 : free_p = false;
701 : }
702 : }
703 :
704 : /* delete client */
705 6 : if (free_p)
706 6 : zserv_client_free(client);
707 6 : }
708 :
709 : /*
710 : * This task is scheduled by a ZAPI client pthread on the main pthread when it
711 : * wants to stop itself. When this executes, the client connection should
712 : * already have been closed and the thread will most likely have died, but its
713 : * resources still need to be cleaned up.
714 : */
715 6 : static void zserv_handle_client_fail(struct event *thread)
716 : {
717 6 : struct zserv *client = EVENT_ARG(thread);
718 :
719 6 : zserv_close_client(client);
720 6 : }
721 :
722 : /*
723 : * Create a new client.
724 : *
725 : * This is called when a new connection is accept()'d on the ZAPI socket. It
726 : * initializes new client structure, notifies any subscribers of the connection
727 : * event and spawns the client's thread.
728 : *
729 : * sock
730 : * client's socket file descriptor
731 : */
732 6 : static struct zserv *zserv_client_create(int sock)
733 : {
734 6 : struct zserv *client;
735 6 : size_t stream_size =
736 : MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route));
737 6 : int i;
738 6 : afi_t afi;
739 :
740 6 : client = XCALLOC(MTYPE_ZSERV_CLIENT, sizeof(struct zserv));
741 :
742 : /* Make client input/output buffer. */
743 6 : client->sock = sock;
744 6 : client->ibuf_fifo = stream_fifo_new();
745 6 : client->obuf_fifo = stream_fifo_new();
746 6 : client->ibuf_work = stream_new(stream_size);
747 6 : client->obuf_work = stream_new(stream_size);
748 6 : client->connect_time = monotime(NULL);
749 6 : pthread_mutex_init(&client->ibuf_mtx, NULL);
750 6 : pthread_mutex_init(&client->obuf_mtx, NULL);
751 6 : pthread_mutex_init(&client->stats_mtx, NULL);
752 6 : client->wb = buffer_new(0);
753 6 : TAILQ_INIT(&(client->gr_info_queue));
754 :
755 : /* Initialize flags */
756 24 : for (afi = AFI_IP; afi < AFI_MAX; afi++) {
757 594 : for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
758 576 : vrf_bitmap_init(&client->redist[afi][i]);
759 18 : vrf_bitmap_init(&client->redist_default[afi]);
760 18 : vrf_bitmap_init(&client->ridinfo[afi]);
761 18 : vrf_bitmap_init(&client->nhrp_neighinfo[afi]);
762 : }
763 :
764 : /* Add this client to linked list. */
765 12 : frr_with_mutex (&client_mutex) {
766 6 : listnode_add(zrouter.client_list, client);
767 : }
768 :
769 6 : struct frr_pthread_attr zclient_pthr_attrs = {
770 6 : .start = frr_pthread_attr_default.start,
771 6 : .stop = frr_pthread_attr_default.stop
772 : };
773 12 : client->pthread =
774 6 : frr_pthread_new(&zclient_pthr_attrs, "Zebra API client thread",
775 : "zebra_apic");
776 :
777 : /* start read loop */
778 6 : zserv_client_event(client, ZSERV_CLIENT_READ);
779 :
780 : /* call callbacks */
781 6 : hook_call(zserv_client_connect, client);
782 :
783 : /* start pthread */
784 6 : frr_pthread_run(client->pthread, NULL);
785 :
786 6 : return client;
787 : }
788 :
789 : /*
790 : * Retrieve a client object by the complete tuple of
791 : * {protocol, instance, session}. This version supports use
792 : * from a different pthread: the object will be returned marked
793 : * in-use. The caller *must* release the client object with the
794 : * release_client() api, to ensure that the in-use marker is cleared properly.
795 : */
796 0 : struct zserv *zserv_acquire_client(uint8_t proto, unsigned short instance,
797 : uint32_t session_id)
798 : {
799 0 : struct zserv *client = NULL;
800 :
801 0 : frr_with_mutex (&client_mutex) {
802 0 : client = find_client_internal(proto, instance, session_id);
803 0 : if (client) {
804 : /* Don't return a dead/closed client object */
805 0 : if (client->is_closed)
806 : client = NULL;
807 : else
808 0 : client->busy_count++;
809 : }
810 : }
811 :
812 0 : return client;
813 : }
814 :
815 : /*
816 : * Release a client object that was acquired with the acquire_client() api.
817 : * After this has been called, the caller must not use the client pointer -
818 : * it may be freed if the client has closed.
819 : */
820 0 : void zserv_release_client(struct zserv *client)
821 : {
822 : /*
823 : * Once we've decremented the client object's refcount, it's possible
824 : * for it to be deleted as soon as we release the lock, so we won't
825 : * touch the object again.
826 : */
827 0 : frr_with_mutex (&client_mutex) {
828 0 : client->busy_count--;
829 :
830 0 : if (client->busy_count <= 0) {
831 : /*
832 : * No more users of the client object. If the client
833 : * session is closed, schedule cleanup on the zebra
834 : * main pthread.
835 : */
836 0 : if (client->is_closed)
837 0 : event_add_event(zrouter.master,
838 : zserv_handle_client_fail,
839 : client, 0, &client->t_cleanup);
840 : }
841 : }
842 :
843 : /*
844 : * Cleanup must take place on the zebra main pthread, so we've
845 : * scheduled an event.
846 : */
847 0 : }
848 :
849 : /*
850 : * Accept socket connection.
851 : */
852 6 : static void zserv_accept(struct event *thread)
853 : {
854 6 : int accept_sock;
855 6 : int client_sock;
856 6 : struct sockaddr_in client;
857 6 : socklen_t len;
858 :
859 6 : accept_sock = EVENT_FD(thread);
860 :
861 : /* Reregister myself. */
862 6 : zserv_event(NULL, ZSERV_ACCEPT);
863 :
864 6 : len = sizeof(struct sockaddr_in);
865 6 : client_sock = accept(accept_sock, (struct sockaddr *)&client, &len);
866 :
867 6 : if (client_sock < 0) {
868 0 : flog_err_sys(EC_LIB_SOCKET, "Can't accept zebra socket: %s",
869 : safe_strerror(errno));
870 0 : return;
871 : }
872 :
873 : /* Make client socket non-blocking. */
874 6 : set_nonblocking(client_sock);
875 :
876 : /* Create new zebra client. */
877 6 : zserv_client_create(client_sock);
878 : }
879 :
880 2 : void zserv_close(void)
881 : {
882 : /*
883 : * On shutdown, let's close the socket down
884 : * so that long running processes of killing the
885 : * routing table doesn't leave us in a bad
886 : * state where a client tries to reconnect
887 : */
888 2 : close(zsock);
889 2 : zsock = -1;
890 :
891 : /* Free client list's mutex */
892 2 : pthread_mutex_destroy(&client_mutex);
893 2 : }
894 :
895 2 : void zserv_start(char *path)
896 : {
897 2 : int ret;
898 2 : mode_t old_mask;
899 2 : struct sockaddr_storage sa;
900 2 : socklen_t sa_len;
901 :
902 2 : if (!frr_zclient_addr(&sa, &sa_len, path))
903 : /* should be caught in zebra main() */
904 0 : return;
905 :
906 : /* Set umask */
907 2 : old_mask = umask(0077);
908 :
909 : /* Make UNIX domain socket. */
910 2 : zsock = socket(sa.ss_family, SOCK_STREAM, 0);
911 2 : if (zsock < 0) {
912 0 : flog_err_sys(EC_LIB_SOCKET, "Can't create zserv socket: %s",
913 : safe_strerror(errno));
914 0 : return;
915 : }
916 :
917 2 : if (sa.ss_family != AF_UNIX) {
918 0 : sockopt_reuseaddr(zsock);
919 0 : sockopt_reuseport(zsock);
920 : } else {
921 2 : struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
922 2 : if (suna->sun_path[0])
923 2 : unlink(suna->sun_path);
924 : }
925 :
926 2 : setsockopt_so_recvbuf(zsock, 1048576);
927 2 : setsockopt_so_sendbuf(zsock, 1048576);
928 :
929 4 : frr_with_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) {
930 2 : ret = bind(zsock, (struct sockaddr *)&sa, sa_len);
931 : }
932 2 : if (ret < 0) {
933 0 : flog_err_sys(EC_LIB_SOCKET, "Can't bind zserv socket on %s: %s",
934 : path, safe_strerror(errno));
935 0 : close(zsock);
936 0 : zsock = -1;
937 0 : return;
938 : }
939 :
940 2 : ret = listen(zsock, 5);
941 2 : if (ret < 0) {
942 0 : flog_err_sys(EC_LIB_SOCKET,
943 : "Can't listen to zserv socket %s: %s", path,
944 : safe_strerror(errno));
945 0 : close(zsock);
946 0 : zsock = -1;
947 0 : return;
948 : }
949 :
950 2 : umask(old_mask);
951 :
952 2 : zserv_event(NULL, ZSERV_ACCEPT);
953 : }
954 :
955 46 : void zserv_event(struct zserv *client, enum zserv_event event)
956 : {
957 46 : switch (event) {
958 8 : case ZSERV_ACCEPT:
959 8 : event_add_read(zrouter.master, zserv_accept, NULL, zsock, NULL);
960 8 : break;
961 32 : case ZSERV_PROCESS_MESSAGES:
962 32 : event_add_event(zrouter.master, zserv_process_messages, client,
963 : 0, &client->t_process);
964 32 : break;
965 6 : case ZSERV_HANDLE_CLIENT_FAIL:
966 6 : event_add_event(zrouter.master, zserv_handle_client_fail,
967 : client, 0, &client->t_cleanup);
968 : }
969 46 : }
970 :
971 :
972 : /* General purpose ---------------------------------------------------------- */
973 :
974 : #define ZEBRA_TIME_BUF 32
975 0 : static char *zserv_time_buf(time_t *time1, char *buf, int buflen)
976 : {
977 0 : time_t now;
978 :
979 0 : assert(buf != NULL);
980 0 : assert(buflen >= ZEBRA_TIME_BUF);
981 0 : assert(time1 != NULL);
982 :
983 0 : if (!*time1) {
984 0 : snprintf(buf, buflen, "never ");
985 0 : return (buf);
986 : }
987 :
988 0 : now = monotime(NULL);
989 0 : now -= *time1;
990 :
991 0 : frrtime_to_interval(now, buf, buflen);
992 :
993 0 : return buf;
994 : }
995 :
996 : /* Display client info details */
997 0 : static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
998 : {
999 0 : char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
1000 0 : char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF];
1001 0 : time_t connect_time, last_read_time, last_write_time;
1002 0 : uint32_t last_read_cmd, last_write_cmd;
1003 :
1004 0 : vty_out(vty, "Client: %s", zebra_route_string(client->proto));
1005 0 : if (client->instance)
1006 0 : vty_out(vty, " Instance: %u", client->instance);
1007 0 : if (client->session_id)
1008 0 : vty_out(vty, " [%u]", client->session_id);
1009 0 : vty_out(vty, "\n");
1010 :
1011 0 : vty_out(vty, "------------------------ \n");
1012 0 : vty_out(vty, "FD: %d \n", client->sock);
1013 :
1014 0 : frr_with_mutex (&client->stats_mtx) {
1015 0 : connect_time = client->connect_time;
1016 0 : last_read_time = client->last_read_time;
1017 0 : last_write_time = client->last_write_time;
1018 :
1019 0 : last_read_cmd = client->last_read_cmd;
1020 0 : last_write_cmd = client->last_write_cmd;
1021 : }
1022 :
1023 0 : vty_out(vty, "Connect Time: %s \n",
1024 : zserv_time_buf(&connect_time, cbuf, ZEBRA_TIME_BUF));
1025 0 : if (client->nh_reg_time) {
1026 0 : vty_out(vty, "Nexthop Registry Time: %s \n",
1027 : zserv_time_buf(&client->nh_reg_time, nhbuf,
1028 : ZEBRA_TIME_BUF));
1029 0 : if (client->nh_last_upd_time)
1030 0 : vty_out(vty, "Nexthop Last Update Time: %s \n",
1031 : zserv_time_buf(&client->nh_last_upd_time, mbuf,
1032 : ZEBRA_TIME_BUF));
1033 : else
1034 0 : vty_out(vty, "No Nexthop Update sent\n");
1035 : } else
1036 0 : vty_out(vty, "Not registered for Nexthop Updates\n");
1037 :
1038 0 : vty_out(vty,
1039 : "Client will %sbe notified about the status of its routes.\n",
1040 0 : client->notify_owner ? "" : "Not ");
1041 :
1042 0 : vty_out(vty, "Last Msg Rx Time: %s \n",
1043 : zserv_time_buf(&last_read_time, rbuf, ZEBRA_TIME_BUF));
1044 0 : vty_out(vty, "Last Msg Tx Time: %s \n",
1045 : zserv_time_buf(&last_write_time, wbuf, ZEBRA_TIME_BUF));
1046 0 : if (last_read_cmd)
1047 0 : vty_out(vty, "Last Rcvd Cmd: %s \n",
1048 : zserv_command_string(last_read_cmd));
1049 0 : if (last_write_cmd)
1050 0 : vty_out(vty, "Last Sent Cmd: %s \n",
1051 : zserv_command_string(last_write_cmd));
1052 0 : vty_out(vty, "\n");
1053 :
1054 0 : vty_out(vty, "Type Add Update Del \n");
1055 0 : vty_out(vty, "================================================== \n");
1056 0 : vty_out(vty, "IPv4 %-12u%-12u%-12u\n", client->v4_route_add_cnt,
1057 : client->v4_route_upd8_cnt, client->v4_route_del_cnt);
1058 0 : vty_out(vty, "IPv6 %-12u%-12u%-12u\n", client->v6_route_add_cnt,
1059 : client->v6_route_upd8_cnt, client->v6_route_del_cnt);
1060 0 : vty_out(vty, "Redist:v4 %-12u%-12u%-12u\n", client->redist_v4_add_cnt,
1061 : 0, client->redist_v4_del_cnt);
1062 0 : vty_out(vty, "Redist:v6 %-12u%-12u%-12u\n", client->redist_v6_add_cnt,
1063 : 0, client->redist_v6_del_cnt);
1064 0 : vty_out(vty, "VRF %-12u%-12u%-12u\n", client->vrfadd_cnt, 0,
1065 : client->vrfdel_cnt);
1066 0 : vty_out(vty, "Connected %-12u%-12u%-12u\n", client->ifadd_cnt, 0,
1067 : client->ifdel_cnt);
1068 0 : vty_out(vty, "Interface %-12u%-12u%-12u\n", client->ifup_cnt, 0,
1069 : client->ifdown_cnt);
1070 0 : vty_out(vty, "Intf Addr %-12u%-12u%-12u\n",
1071 : client->connected_rt_add_cnt, 0, client->connected_rt_del_cnt);
1072 0 : vty_out(vty, "BFD peer %-12u%-12u%-12u\n", client->bfd_peer_add_cnt,
1073 : client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
1074 0 : vty_out(vty, "NHT v4 %-12u%-12u%-12u\n",
1075 : client->v4_nh_watch_add_cnt, 0, client->v4_nh_watch_rem_cnt);
1076 0 : vty_out(vty, "NHT v6 %-12u%-12u%-12u\n",
1077 : client->v6_nh_watch_add_cnt, 0, client->v6_nh_watch_rem_cnt);
1078 0 : vty_out(vty, "VxLAN SG %-12u%-12u%-12u\n", client->vxlan_sg_add_cnt,
1079 : 0, client->vxlan_sg_del_cnt);
1080 0 : vty_out(vty, "VNI %-12u%-12u%-12u\n", client->vniadd_cnt, 0,
1081 : client->vnidel_cnt);
1082 0 : vty_out(vty, "L3-VNI %-12u%-12u%-12u\n", client->l3vniadd_cnt, 0,
1083 : client->l3vnidel_cnt);
1084 0 : vty_out(vty, "MAC-IP %-12u%-12u%-12u\n", client->macipadd_cnt, 0,
1085 : client->macipdel_cnt);
1086 0 : vty_out(vty, "ES %-12u%-12u%-12u\n", client->local_es_add_cnt,
1087 : 0, client->local_es_del_cnt);
1088 0 : vty_out(vty, "ES-EVI %-12u%-12u%-12u\n",
1089 : client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt);
1090 0 : vty_out(vty, "Errors: %u\n", client->error_cnt);
1091 :
1092 : #if defined DEV_BUILD
1093 : vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n",
1094 : client->ibuf_fifo->count, client->ibuf_fifo->max_count,
1095 : client->obuf_fifo->count, client->obuf_fifo->max_count);
1096 : #endif
1097 0 : vty_out(vty, "\n");
1098 0 : }
1099 :
1100 : /* Display stale client information */
1101 0 : static void zebra_show_stale_client_detail(struct vty *vty,
1102 : struct zserv *client)
1103 : {
1104 0 : char buf[PREFIX2STR_BUFFER];
1105 0 : time_t uptime;
1106 0 : struct client_gr_info *info = NULL;
1107 0 : struct zserv *s = NULL;
1108 0 : bool first_p = true;
1109 :
1110 0 : TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
1111 0 : if (first_p) {
1112 0 : vty_out(vty, "Stale Client Information\n");
1113 0 : vty_out(vty, "------------------------\n");
1114 :
1115 0 : if (client->instance)
1116 0 : vty_out(vty, " Instance: %u", client->instance);
1117 0 : if (client->session_id)
1118 0 : vty_out(vty, " [%u]", client->session_id);
1119 :
1120 : first_p = false;
1121 : }
1122 :
1123 0 : vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));
1124 0 : vty_out(vty, "Capabilities : ");
1125 0 : switch (info->capabilities) {
1126 0 : case ZEBRA_CLIENT_GR_CAPABILITIES:
1127 0 : vty_out(vty, "Graceful Restart(%u seconds)\n",
1128 : info->stale_removal_time);
1129 0 : break;
1130 0 : case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
1131 : case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
1132 : case ZEBRA_CLIENT_GR_DISABLE:
1133 : case ZEBRA_CLIENT_RIB_STALE_TIME:
1134 0 : vty_out(vty, "None\n");
1135 0 : break;
1136 : }
1137 :
1138 0 : if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)) {
1139 0 : if (info->stale_client_ptr) {
1140 0 : s = (struct zserv *)(info->stale_client_ptr);
1141 0 : uptime = monotime(NULL);
1142 0 : uptime -= s->restart_time;
1143 :
1144 0 : frrtime_to_interval(uptime, buf, sizeof(buf));
1145 :
1146 0 : vty_out(vty, "Last restart time : %s ago\n",
1147 : buf);
1148 :
1149 0 : vty_out(vty, "Stalepath removal time: %d sec\n",
1150 : info->stale_removal_time);
1151 0 : if (info->t_stale_removal) {
1152 0 : vty_out(vty,
1153 : "Stale delete timer: %ld sec\n",
1154 : event_timer_remain_second(
1155 : info->t_stale_removal));
1156 : }
1157 : }
1158 : }
1159 : }
1160 0 : vty_out(vty, "\n");
1161 0 : return;
1162 : }
1163 :
1164 0 : static void zebra_show_client_brief(struct vty *vty, struct zserv *client)
1165 : {
1166 0 : char client_string[80];
1167 0 : char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF];
1168 0 : char wbuf[ZEBRA_TIME_BUF];
1169 0 : time_t connect_time, last_read_time, last_write_time;
1170 :
1171 0 : frr_with_mutex (&client->stats_mtx) {
1172 0 : connect_time = client->connect_time;
1173 0 : last_read_time = client->last_read_time;
1174 0 : last_write_time = client->last_write_time;
1175 : }
1176 :
1177 0 : if (client->instance || client->session_id)
1178 0 : snprintfrr(client_string, sizeof(client_string), "%s[%u:%u]",
1179 0 : zebra_route_string(client->proto), client->instance,
1180 : client->session_id);
1181 : else
1182 0 : snprintfrr(client_string, sizeof(client_string), "%s",
1183 0 : zebra_route_string(client->proto));
1184 :
1185 0 : vty_out(vty, "%-10s%12s %12s%12s %10d/%-10d %10d/%-10d\n",
1186 : client_string,
1187 : zserv_time_buf(&connect_time, cbuf, ZEBRA_TIME_BUF),
1188 : zserv_time_buf(&last_read_time, rbuf, ZEBRA_TIME_BUF),
1189 : zserv_time_buf(&last_write_time, wbuf, ZEBRA_TIME_BUF),
1190 0 : client->v4_route_add_cnt + client->v4_route_upd8_cnt,
1191 : client->v4_route_del_cnt,
1192 0 : client->v6_route_add_cnt + client->v6_route_upd8_cnt,
1193 : client->v6_route_del_cnt);
1194 0 : }
1195 :
1196 : /*
1197 : * Common logic that searches the client list for a zapi client; this
1198 : * MUST be called holding the client list mutex.
1199 : */
1200 28 : static struct zserv *find_client_internal(uint8_t proto,
1201 : unsigned short instance,
1202 : uint32_t session_id)
1203 : {
1204 28 : struct listnode *node, *nnode;
1205 28 : struct zserv *client = NULL;
1206 :
1207 86 : for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
1208 32 : if (client->proto == proto && client->instance == instance &&
1209 2 : client->session_id == session_id)
1210 : break;
1211 : }
1212 :
1213 28 : return client;
1214 : }
1215 :
1216 : /*
1217 : * Public api that searches for a client session; this version is
1218 : * used from the zebra main pthread.
1219 : */
1220 28 : struct zserv *zserv_find_client(uint8_t proto, unsigned short instance)
1221 : {
1222 28 : struct zserv *client;
1223 :
1224 28 : frr_with_mutex (&client_mutex) {
1225 28 : client = find_client_internal(proto, instance, 0);
1226 : }
1227 :
1228 28 : return client;
1229 : }
1230 :
1231 : /*
1232 : * Retrieve a client by its protocol, instance number, and session id.
1233 : */
1234 0 : struct zserv *zserv_find_client_session(uint8_t proto, unsigned short instance,
1235 : uint32_t session_id)
1236 : {
1237 0 : struct zserv *client;
1238 :
1239 0 : frr_with_mutex (&client_mutex) {
1240 0 : client = find_client_internal(proto, instance, session_id);
1241 : }
1242 :
1243 0 : return client;
1244 :
1245 : }
1246 :
1247 : /* This command is for debugging purpose. */
1248 0 : DEFUN (show_zebra_client,
1249 : show_zebra_client_cmd,
1250 : "show zebra client",
1251 : SHOW_STR
1252 : ZEBRA_STR
1253 : "Client information\n")
1254 : {
1255 0 : struct listnode *node;
1256 0 : struct zserv *client;
1257 :
1258 0 : for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
1259 0 : zebra_show_client_detail(vty, client);
1260 : /* Show GR info if present */
1261 0 : zebra_show_stale_client_detail(vty, client);
1262 : }
1263 :
1264 0 : return CMD_SUCCESS;
1265 : }
1266 :
1267 : /* This command is for debugging purpose. */
1268 0 : DEFUN (show_zebra_client_summary,
1269 : show_zebra_client_summary_cmd,
1270 : "show zebra client summary",
1271 : SHOW_STR
1272 : ZEBRA_STR
1273 : "Client information brief\n"
1274 : "Brief Summary\n")
1275 : {
1276 0 : struct listnode *node;
1277 0 : struct zserv *client;
1278 :
1279 0 : vty_out(vty,
1280 : "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes\n");
1281 0 : vty_out(vty,
1282 : "------------------------------------------------------------------------------------------\n");
1283 :
1284 0 : for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
1285 0 : zebra_show_client_brief(vty, client);
1286 :
1287 0 : vty_out(vty, "Routes column shows (added+updated)/deleted\n");
1288 0 : return CMD_SUCCESS;
1289 : }
1290 :
1291 6 : static int zserv_client_close_cb(struct zserv *closed_client)
1292 : {
1293 6 : struct listnode *node, *nnode;
1294 6 : struct zserv *client = NULL;
1295 :
1296 18 : for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
1297 6 : if (client->proto == closed_client->proto)
1298 2 : continue;
1299 :
1300 4 : zsend_client_close_notify(client, closed_client);
1301 : }
1302 :
1303 6 : return 0;
1304 : }
1305 :
1306 2 : void zserv_init(void)
1307 : {
1308 : /* Client list init. */
1309 2 : zrouter.client_list = list_new();
1310 2 : zrouter.stale_client_list = list_new();
1311 :
1312 : /* Misc init. */
1313 2 : zsock = -1;
1314 2 : pthread_mutex_init(&client_mutex, NULL);
1315 :
1316 2 : install_element(ENABLE_NODE, &show_zebra_client_cmd);
1317 2 : install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
1318 :
1319 2 : hook_register(zserv_client_close, zserv_client_close_cb);
1320 2 : }
|