back to topotato report
topotato coverage report
Current view: top level - zebra - zebra_opaque.c (source / functions) Hit Total Coverage
Test: test_bgp_dont_capability_negotiate.py::BGPDontCapabilityNegotiate Lines: 71 271 26.2 %
Date: 2023-02-24 18:37:16 Functions: 11 20 55.0 %

          Line data    Source code
       1             : /*
       2             :  * Zebra opaque message handler module
       3             :  * Copyright (c) 2020 Volta Networks, Inc.
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation; either version 2 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful, but
      11             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : 
      20             : 
      21             : #include <zebra.h>
      22             : #include "lib/debug.h"
      23             : #include "lib/frr_pthread.h"
      24             : #include "lib/stream.h"
      25             : #include "zebra/debug.h"
      26             : #include "zebra/zserv.h"
      27             : #include "zebra/zebra_opaque.h"
      28             : #include "zebra/rib.h"
      29             : 
      30             : /* Mem type */
      31           6 : DEFINE_MTYPE_STATIC(ZEBRA, OPQ, "ZAPI Opaque Information");
      32             : 
      33             : /* Hash to hold message registration info from zapi clients */
      34             : PREDECL_HASH(opq_regh);
      35             : 
      36             : /* Registered client info */
      37             : struct opq_client_reg {
      38             :         int proto;
      39             :         int instance;
      40             :         uint32_t session_id;
      41             : 
      42             :         struct opq_client_reg *next;
      43             :         struct opq_client_reg *prev;
      44             : };
      45             : 
      46             : /* Opaque message registration info */
      47             : struct opq_msg_reg {
      48             :         struct opq_regh_item item;
      49             : 
      50             :         /* Message type */
      51             :         uint32_t type;
      52             : 
      53             :         struct opq_client_reg *clients;
      54             : };
      55             : 
      56             : /* Registration helper prototypes */
      57             : static uint32_t registration_hash(const struct opq_msg_reg *reg);
      58             : static int registration_compare(const struct opq_msg_reg *reg1,
      59             :                                 const struct opq_msg_reg *reg2);
      60             : 
      61           4 : DECLARE_HASH(opq_regh, struct opq_msg_reg, item, registration_compare,
      62             :              registration_hash);
      63             : 
      64             : static struct opq_regh_head opq_reg_hash;
      65             : 
      66             : /*
      67             :  * Globals
      68             :  */
      69             : static struct zebra_opaque_globals {
      70             : 
      71             :         /* Sentinel for run or start of shutdown */
      72             :         _Atomic uint32_t run;
      73             : 
      74             :         /* Limit number of pending, unprocessed updates */
      75             :         _Atomic uint32_t max_queued_updates;
      76             : 
      77             :         /* Limit number of new messages dequeued at once, to pace an
      78             :          * incoming burst.
      79             :          */
      80             :         uint32_t msgs_per_cycle;
      81             : 
      82             :         /* Stats: counters of incoming messages, errors, and yields (when
      83             :          * the limit has been reached.)
      84             :          */
      85             :         _Atomic uint32_t msgs_in;
      86             :         _Atomic uint32_t msg_errors;
      87             :         _Atomic uint32_t yields;
      88             : 
      89             :         /* pthread */
      90             :         struct frr_pthread *pthread;
      91             : 
      92             :         /* Event-delivery context 'master' for the module */
      93             :         struct thread_master *master;
      94             : 
      95             :         /* Event/'thread' pointer for queued zapi messages */
      96             :         struct thread *t_msgs;
      97             : 
      98             :         /* Input fifo queue to the module, and lock to protect it. */
      99             :         pthread_mutex_t mutex;
     100             :         struct stream_fifo in_fifo;
     101             : 
     102             : } zo_info;
     103             : 
     104             : /* Name string for debugs/logs */
     105             : static const char LOG_NAME[] = "Zebra Opaque";
     106             : 
     107             : /* Prototypes */
     108             : 
     109             : /* Main event loop, processing incoming message queue */
     110             : static void process_messages(struct thread *event);
     111             : static int handle_opq_registration(const struct zmsghdr *hdr,
     112             :                                    struct stream *msg);
     113             : static int handle_opq_unregistration(const struct zmsghdr *hdr,
     114             :                                      struct stream *msg);
     115             : static int dispatch_opq_messages(struct stream_fifo *msg_fifo);
     116             : static struct opq_msg_reg *opq_reg_lookup(uint32_t type);
     117             : static bool opq_client_match(const struct opq_client_reg *client,
     118             :                              const struct zapi_opaque_reg_info *info);
     119             : static struct opq_msg_reg *opq_reg_alloc(uint32_t type);
     120             : static void opq_reg_free(struct opq_msg_reg **reg);
     121             : static struct opq_client_reg *opq_client_alloc(
     122             :         const struct zapi_opaque_reg_info *info);
     123             : static void opq_client_free(struct opq_client_reg **client);
     124             : static const char *opq_client2str(char *buf, size_t buflen,
     125             :                                   const struct opq_client_reg *client);
     126             : 
     127             : /*
     128             :  * Initialize the module at startup
     129             :  */
     130           2 : void zebra_opaque_init(void)
     131             : {
     132           2 :         memset(&zo_info, 0, sizeof(zo_info));
     133             : 
     134           2 :         pthread_mutex_init(&zo_info.mutex, NULL);
     135           2 :         stream_fifo_init(&zo_info.in_fifo);
     136             : 
     137           2 :         zo_info.msgs_per_cycle = ZEBRA_OPAQUE_MSG_LIMIT;
     138           2 : }
     139             : 
     140             : /*
     141             :  * Start the module pthread. This step is run later than the
     142             :  * 'init' step, in case zebra has fork-ed.
     143             :  */
     144           2 : void zebra_opaque_start(void)
     145             : {
     146           2 :         struct frr_pthread_attr pattr = {
     147           2 :                 .start = frr_pthread_attr_default.start,
     148           2 :                 .stop = frr_pthread_attr_default.stop
     149             :         };
     150             : 
     151           2 :         if (IS_ZEBRA_DEBUG_EVENT)
     152           0 :                 zlog_debug("%s module starting", LOG_NAME);
     153             : 
     154             :         /* Start pthread */
     155           2 :         zo_info.pthread = frr_pthread_new(&pattr, "Zebra Opaque thread",
     156             :                                           "zebra_opaque");
     157             : 
     158             :         /* Associate event 'master' */
     159           2 :         zo_info.master = zo_info.pthread->master;
     160             : 
     161           2 :         atomic_store_explicit(&zo_info.run, 1, memory_order_relaxed);
     162             : 
     163             :         /* Enqueue an initial event for the pthread */
     164           2 :         thread_add_event(zo_info.master, process_messages, NULL, 0,
     165             :                          &zo_info.t_msgs);
     166             : 
     167             :         /* And start the pthread */
     168           2 :         frr_pthread_run(zo_info.pthread, NULL);
     169           2 : }
     170             : 
     171             : /*
     172             :  * Module stop, halting the dedicated pthread; called from the main pthread.
     173             :  */
     174           2 : void zebra_opaque_stop(void)
     175             : {
     176           2 :         if (IS_ZEBRA_DEBUG_EVENT)
     177           0 :                 zlog_debug("%s module stop", LOG_NAME);
     178             : 
     179           2 :         atomic_store_explicit(&zo_info.run, 0, memory_order_relaxed);
     180             : 
     181           2 :         frr_pthread_stop(zo_info.pthread, NULL);
     182             : 
     183           2 :         frr_pthread_destroy(zo_info.pthread);
     184             : 
     185           2 :         if (IS_ZEBRA_DEBUG_EVENT)
     186           0 :                 zlog_debug("%s module stop complete", LOG_NAME);
     187           2 : }
     188             : 
     189             : /*
     190             :  * Module final cleanup, called from the zebra main pthread.
     191             :  */
     192           2 : void zebra_opaque_finish(void)
     193             : {
     194           2 :         struct opq_msg_reg *reg;
     195           2 :         struct opq_client_reg *client;
     196             : 
     197           2 :         if (IS_ZEBRA_DEBUG_EVENT)
     198           0 :                 zlog_debug("%s module shutdown", LOG_NAME);
     199             : 
     200             :         /* Clear out registration info */
     201           2 :         while ((reg = opq_regh_pop(&opq_reg_hash)) != NULL) {
     202           0 :                 client = reg->clients;
     203           0 :                 while (client) {
     204           0 :                         reg->clients = client->next;
     205           0 :                         opq_client_free(&client);
     206           0 :                         client = reg->clients;
     207             :                 }
     208             : 
     209           2 :                 opq_reg_free(&reg);
     210             :         }
     211             : 
     212           2 :         opq_regh_fini(&opq_reg_hash);
     213             : 
     214           2 :         pthread_mutex_destroy(&zo_info.mutex);
     215           2 :         stream_fifo_deinit(&zo_info.in_fifo);
     216           2 : }
     217             : 
     218             : /*
     219             :  * Does this module handle (intercept) the specified zapi message type?
     220             :  */
     221          56 : bool zebra_opaque_handles_msgid(uint16_t id)
     222             : {
     223          56 :         bool ret = false;
     224             : 
     225          56 :         switch (id) {
     226           0 :         case ZEBRA_OPAQUE_MESSAGE:
     227             :         case ZEBRA_OPAQUE_REGISTER:
     228             :         case ZEBRA_OPAQUE_UNREGISTER:
     229           0 :                 ret = true;
     230           0 :                 break;
     231             :         default:
     232             :                 break;
     233             :         }
     234             : 
     235          56 :         return ret;
     236             : }
     237             : 
     238             : /*
     239             :  * Enqueue a batch of messages for processing - this is the public api
     240             :  * used from the zapi processing threads.
     241             :  */
     242           0 : uint32_t zebra_opaque_enqueue_batch(struct stream_fifo *batch)
     243             : {
     244           0 :         uint32_t counter = 0;
     245           0 :         struct stream *msg;
     246             : 
     247             :         /* Dequeue messages from the incoming batch, and save them
     248             :          * on the module fifo.
     249             :          */
     250           0 :         frr_with_mutex (&zo_info.mutex) {
     251           0 :                 msg = stream_fifo_pop(batch);
     252           0 :                 while (msg) {
     253           0 :                         stream_fifo_push(&zo_info.in_fifo, msg);
     254           0 :                         counter++;
     255           0 :                         msg = stream_fifo_pop(batch);
     256             :                 }
     257             :         }
     258             : 
     259             :         /* Schedule module pthread to process the batch */
     260           0 :         if (counter > 0) {
     261           0 :                 if (IS_ZEBRA_DEBUG_RECV && IS_ZEBRA_DEBUG_DETAIL)
     262           0 :                         zlog_debug("%s: received %u messages",
     263             :                                    __func__, counter);
     264           0 :                 thread_add_event(zo_info.master, process_messages, NULL, 0,
     265             :                                  &zo_info.t_msgs);
     266             :         }
     267             : 
     268           0 :         return counter;
     269             : }
     270             : 
     271             : /*
     272             :  * Pthread event loop, process the incoming message queue.
     273             :  */
     274           2 : static void process_messages(struct thread *event)
     275             : {
     276           2 :         struct stream_fifo fifo;
     277           2 :         struct stream *msg;
     278           2 :         uint32_t i;
     279           2 :         bool need_resched = false;
     280             : 
     281           2 :         stream_fifo_init(&fifo);
     282             : 
     283             :         /* Check for zebra shutdown */
     284           2 :         if (atomic_load_explicit(&zo_info.run, memory_order_relaxed) == 0)
     285           0 :                 goto done;
     286             : 
     287             :         /*
     288             :          * Dequeue some messages from the incoming queue, temporarily
     289             :          * save them on the local fifo
     290             :          */
     291           4 :         frr_with_mutex (&zo_info.mutex) {
     292             : 
     293           2 :                 for (i = 0; i < zo_info.msgs_per_cycle; i++) {
     294           2 :                         msg = stream_fifo_pop(&zo_info.in_fifo);
     295           2 :                         if (msg == NULL)
     296             :                                 break;
     297             : 
     298           0 :                         stream_fifo_push(&fifo, msg);
     299             :                 }
     300             : 
     301             :                 /*
     302             :                  * We may need to reschedule, if there are still
     303             :                  * queued messages
     304             :                  */
     305           2 :                 if (stream_fifo_head(&zo_info.in_fifo) != NULL)
     306           0 :                         need_resched = true;
     307             :         }
     308             : 
     309             :         /* Update stats */
     310           2 :         atomic_fetch_add_explicit(&zo_info.msgs_in, i, memory_order_relaxed);
     311             : 
     312             :         /* Check for zebra shutdown */
     313           2 :         if (atomic_load_explicit(&zo_info.run, memory_order_relaxed) == 0) {
     314           0 :                 need_resched = false;
     315           0 :                 goto done;
     316             :         }
     317             : 
     318           2 :         if (IS_ZEBRA_DEBUG_RECV && IS_ZEBRA_DEBUG_DETAIL)
     319           0 :                 zlog_debug("%s: processing %u messages", __func__, i);
     320             : 
     321             :         /*
     322             :          * Process the messages from the temporary fifo. We send the whole
     323             :          * fifo so that we can take advantage of batching internally. Note
     324             :          * that registration/deregistration messages are handled here also.
     325             :          */
     326           2 :         dispatch_opq_messages(&fifo);
     327             : 
     328           2 : done:
     329             : 
     330           2 :         if (need_resched) {
     331           0 :                 atomic_fetch_add_explicit(&zo_info.yields, 1,
     332             :                                           memory_order_relaxed);
     333           0 :                 thread_add_event(zo_info.master, process_messages, NULL, 0,
     334             :                                  &zo_info.t_msgs);
     335             :         }
     336             : 
     337             :         /* This will also free any leftover messages, in the shutdown case */
     338           2 :         stream_fifo_deinit(&fifo);
     339           2 : }
     340             : 
     341             : /*
     342             :  * Process (dispatch) or drop opaque messages.
     343             :  */
     344           2 : static int dispatch_opq_messages(struct stream_fifo *msg_fifo)
     345             : {
     346           2 :         struct stream *msg, *dup;
     347           2 :         struct zmsghdr hdr;
     348           2 :         struct zapi_opaque_msg info;
     349           2 :         struct opq_msg_reg *reg;
     350           2 :         int ret;
     351           2 :         struct opq_client_reg *client;
     352           2 :         struct zserv *zclient;
     353           2 :         char buf[50];
     354             : 
     355           2 :         while ((msg = stream_fifo_pop(msg_fifo)) != NULL) {
     356           0 :                 zapi_parse_header(msg, &hdr);
     357           0 :                 hdr.length -= ZEBRA_HEADER_SIZE;
     358             : 
     359             :                 /* Handle client registration messages */
     360           0 :                 if (hdr.command == ZEBRA_OPAQUE_REGISTER) {
     361           0 :                         handle_opq_registration(&hdr, msg);
     362           0 :                         continue;
     363           0 :                 } else if (hdr.command == ZEBRA_OPAQUE_UNREGISTER) {
     364           0 :                         handle_opq_unregistration(&hdr, msg);
     365           0 :                         continue;
     366             :                 }
     367             : 
     368             :                 /* We only process OPAQUE messages - drop anything else */
     369           0 :                 if (hdr.command != ZEBRA_OPAQUE_MESSAGE)
     370           0 :                         goto drop_it;
     371             : 
     372             :                 /* Dispatch to any registered ZAPI client(s) */
     373             : 
     374             :                 /* Extract subtype and flags */
     375           0 :                 ret = zclient_opaque_decode(msg, &info);
     376           0 :                 if (ret != 0)
     377           0 :                         goto drop_it;
     378             : 
     379             :                 /* Look up registered ZAPI client(s) */
     380           0 :                 reg = opq_reg_lookup(info.type);
     381           0 :                 if (reg == NULL) {
     382           0 :                         if (IS_ZEBRA_DEBUG_RECV && IS_ZEBRA_DEBUG_DETAIL)
     383           0 :                                 zlog_debug("%s: no registrations for opaque type %u, flags %#x",
     384             :                                            __func__, info.type, info.flags);
     385           0 :                         goto drop_it;
     386             :                 }
     387             : 
     388             :                 /* Reset read pointer, since we'll be re-sending message */
     389           0 :                 stream_set_getp(msg, 0);
     390             : 
     391             :                 /* Send a copy of the message to all registered clients */
     392           0 :                 for (client = reg->clients; client; client = client->next) {
     393           0 :                         dup = NULL;
     394             : 
     395           0 :                         if (CHECK_FLAG(info.flags, ZAPI_OPAQUE_FLAG_UNICAST)) {
     396             : 
     397           0 :                                 if (client->proto != info.proto ||
     398           0 :                                     client->instance != info.instance ||
     399           0 :                                     client->session_id != info.session_id)
     400           0 :                                         continue;
     401             : 
     402           0 :                                 if (IS_ZEBRA_DEBUG_RECV &&
     403             :                                     IS_ZEBRA_DEBUG_DETAIL)
     404           0 :                                         zlog_debug("%s: found matching unicast client %s",
     405             :                                                    __func__,
     406             :                                                    opq_client2str(buf,
     407             :                                                                   sizeof(buf),
     408             :                                                                   client));
     409             : 
     410             :                         } else {
     411             :                                 /* Copy message if more clients */
     412           0 :                                 if (client->next)
     413           0 :                                         dup = stream_dup(msg);
     414             :                         }
     415             : 
     416             :                         /*
     417             :                          * TODO -- this isn't ideal: we're going through an
     418             :                          * acquire/release cycle for each client for each
     419             :                          * message. Replace this with a batching version.
     420             :                          */
     421           0 :                         zclient = zserv_acquire_client(client->proto,
     422           0 :                                                        client->instance,
     423             :                                                        client->session_id);
     424           0 :                         if (zclient) {
     425           0 :                                 if (IS_ZEBRA_DEBUG_SEND &&
     426             :                                     IS_ZEBRA_DEBUG_DETAIL)
     427           0 :                                         zlog_debug("%s: sending %s to client %s",
     428             :                                                    __func__,
     429             :                                                    (dup ? "dup" : "msg"),
     430             :                                                    opq_client2str(buf,
     431             :                                                                   sizeof(buf),
     432             :                                                                   client));
     433             : 
     434             :                                 /*
     435             :                                  * Sending a message actually means enqueuing
     436             :                                  * it for a zapi io pthread to send - so we
     437             :                                  * don't touch the message after this call.
     438             :                                  */
     439           0 :                                 zserv_send_message(zclient, dup ? dup : msg);
     440           0 :                                 if (dup)
     441           0 :                                         dup = NULL;
     442             :                                 else
     443           0 :                                         msg = NULL;
     444             : 
     445           0 :                                 zserv_release_client(zclient);
     446             :                         } else {
     447           0 :                                 if (IS_ZEBRA_DEBUG_RECV &&
     448             :                                     IS_ZEBRA_DEBUG_DETAIL)
     449           0 :                                         zlog_debug("%s: type %u: no zclient for %s",
     450             :                                                    __func__, info.type,
     451             :                                                    opq_client2str(buf,
     452             :                                                                   sizeof(buf),
     453             :                                                                   client));
     454             :                                 /* Registered but gone? */
     455           0 :                                 if (dup)
     456           0 :                                         stream_free(dup);
     457             :                         }
     458             : 
     459             :                         /* If unicast, we're done */
     460           0 :                         if (CHECK_FLAG(info.flags, ZAPI_OPAQUE_FLAG_UNICAST))
     461             :                                 break;
     462             :                 }
     463             : 
     464           0 : drop_it:
     465             : 
     466           0 :                 if (msg)
     467           0 :                         stream_free(msg);
     468             :         }
     469             : 
     470           2 :         return 0;
     471             : }
     472             : 
     473             : /*
     474             :  * Process a register/unregister message
     475             :  */
     476           0 : static int handle_opq_registration(const struct zmsghdr *hdr,
     477             :                                    struct stream *msg)
     478             : {
     479           0 :         int ret = 0;
     480           0 :         struct zapi_opaque_reg_info info;
     481           0 :         struct opq_client_reg *client;
     482           0 :         struct opq_msg_reg key, *reg;
     483           0 :         char buf[50];
     484             : 
     485           0 :         memset(&info, 0, sizeof(info));
     486             : 
     487           0 :         if (zapi_opaque_reg_decode(msg, &info) < 0) {
     488           0 :                 ret = -1;
     489           0 :                 goto done;
     490             :         }
     491             : 
     492           0 :         memset(&key, 0, sizeof(key));
     493             : 
     494           0 :         key.type = info.type;
     495             : 
     496           0 :         reg = opq_regh_find(&opq_reg_hash, &key);
     497           0 :         if (reg) {
     498             :                 /* Look for dup client */
     499           0 :                 for (client = reg->clients; client != NULL;
     500           0 :                      client = client->next) {
     501           0 :                         if (opq_client_match(client, &info))
     502             :                                 break;
     503             :                 }
     504             : 
     505           0 :                 if (client) {
     506             :                         /* Oops - duplicate registration? */
     507           0 :                         if (IS_ZEBRA_DEBUG_RECV)
     508           0 :                                 zlog_debug("%s: duplicate opq reg for client %s",
     509             :                                            __func__,
     510             :                                            opq_client2str(buf, sizeof(buf),
     511             :                                                           client));
     512           0 :                         goto done;
     513             :                 }
     514             : 
     515           0 :                 client = opq_client_alloc(&info);
     516             : 
     517           0 :                 if (IS_ZEBRA_DEBUG_RECV)
     518           0 :                         zlog_debug("%s: client %s registers for %u",
     519             :                                    __func__,
     520             :                                    opq_client2str(buf, sizeof(buf), client),
     521             :                                    info.type);
     522             : 
     523             :                 /* Link client into registration */
     524           0 :                 client->next = reg->clients;
     525           0 :                 if (reg->clients)
     526           0 :                         reg->clients->prev = client;
     527           0 :                 reg->clients = client;
     528             :         } else {
     529             :                 /*
     530             :                  * No existing registrations - create one, add the
     531             :                  * client, and add registration to hash.
     532             :                  */
     533           0 :                 reg = opq_reg_alloc(info.type);
     534           0 :                 client = opq_client_alloc(&info);
     535             : 
     536           0 :                 if (IS_ZEBRA_DEBUG_RECV)
     537           0 :                         zlog_debug("%s: client %s registers for new reg %u",
     538             :                                    __func__,
     539             :                                    opq_client2str(buf, sizeof(buf), client),
     540             :                                    info.type);
     541             : 
     542           0 :                 reg->clients = client;
     543             : 
     544           0 :                 opq_regh_add(&opq_reg_hash, reg);
     545             :         }
     546             : 
     547           0 : done:
     548             : 
     549           0 :         stream_free(msg);
     550           0 :         return ret;
     551             : }
     552             : 
     553             : /*
     554             :  * Process a register/unregister message
     555             :  */
     556           0 : static int handle_opq_unregistration(const struct zmsghdr *hdr,
     557             :                                      struct stream *msg)
     558             : {
     559           0 :         int ret = 0;
     560           0 :         struct zapi_opaque_reg_info info;
     561           0 :         struct opq_client_reg *client;
     562           0 :         struct opq_msg_reg key, *reg;
     563           0 :         char buf[50];
     564             : 
     565           0 :         memset(&info, 0, sizeof(info));
     566             : 
     567           0 :         if (zapi_opaque_reg_decode(msg, &info) < 0) {
     568           0 :                 ret = -1;
     569           0 :                 goto done;
     570             :         }
     571             : 
     572           0 :         memset(&key, 0, sizeof(key));
     573             : 
     574           0 :         key.type = info.type;
     575             : 
     576           0 :         reg = opq_regh_find(&opq_reg_hash, &key);
     577           0 :         if (reg == NULL) {
     578             :                 /* Weird: unregister for unknown message? */
     579           0 :                 if (IS_ZEBRA_DEBUG_RECV)
     580           0 :                         zlog_debug("%s: unknown client %s/%u/%u unregisters for unknown type %u",
     581             :                                    __func__,
     582             :                                    zebra_route_string(info.proto),
     583             :                                    info.instance, info.session_id, info.type);
     584           0 :                 goto done;
     585             :         }
     586             : 
     587             :         /* Look for client */
     588           0 :         for (client = reg->clients; client != NULL;
     589           0 :              client = client->next) {
     590           0 :                 if (opq_client_match(client, &info))
     591             :                         break;
     592             :         }
     593             : 
     594           0 :         if (client == NULL) {
     595             :                 /* Oops - unregister for unknown client? */
     596           0 :                 if (IS_ZEBRA_DEBUG_RECV)
     597           0 :                         zlog_debug("%s: unknown client %s/%u/%u unregisters for %u",
     598             :                                    __func__, zebra_route_string(info.proto),
     599             :                                    info.instance, info.session_id, info.type);
     600           0 :                 goto done;
     601             :         }
     602             : 
     603           0 :         if (IS_ZEBRA_DEBUG_RECV)
     604           0 :                 zlog_debug("%s: client %s unregisters for %u",
     605             :                            __func__, opq_client2str(buf, sizeof(buf), client),
     606             :                            info.type);
     607             : 
     608           0 :         if (client->prev)
     609           0 :                 client->prev->next = client->next;
     610           0 :         if (client->next)
     611           0 :                 client->next->prev = client->prev;
     612           0 :         if (reg->clients == client)
     613           0 :                 reg->clients = client->next;
     614             : 
     615           0 :         opq_client_free(&client);
     616             : 
     617             :         /* Is registration empty now? */
     618           0 :         if (reg->clients == NULL) {
     619           0 :                 opq_regh_del(&opq_reg_hash, reg);
     620           0 :                 opq_reg_free(&reg);
     621             :         }
     622             : 
     623           0 : done:
     624             : 
     625           0 :         stream_free(msg);
     626           0 :         return ret;
     627             : }
     628             : 
     629             : /* Compare utility for registered clients */
     630           0 : static bool opq_client_match(const struct opq_client_reg *client,
     631             :                              const struct zapi_opaque_reg_info *info)
     632             : {
     633           0 :         if (client->proto == info->proto &&
     634           0 :             client->instance == info->instance &&
     635           0 :             client->session_id == info->session_id)
     636             :                 return true;
     637             :         else
     638           0 :                 return false;
     639             : }
     640             : 
     641           0 : static struct opq_msg_reg *opq_reg_lookup(uint32_t type)
     642             : {
     643           0 :         struct opq_msg_reg key, *reg;
     644             : 
     645           0 :         memset(&key, 0, sizeof(key));
     646             : 
     647           0 :         key.type = type;
     648             : 
     649           0 :         reg = opq_regh_find(&opq_reg_hash, &key);
     650             : 
     651           0 :         return reg;
     652             : }
     653             : 
     654           0 : static struct opq_msg_reg *opq_reg_alloc(uint32_t type)
     655             : {
     656           0 :         struct opq_msg_reg *reg;
     657             : 
     658           0 :         reg = XCALLOC(MTYPE_OPQ, sizeof(struct opq_msg_reg));
     659             : 
     660           0 :         reg->type = type;
     661           0 :         INIT_HASH(&reg->item);
     662             : 
     663           0 :         return reg;
     664             : }
     665             : 
     666           0 : static void opq_reg_free(struct opq_msg_reg **reg)
     667             : {
     668           0 :         XFREE(MTYPE_OPQ, (*reg));
     669           0 : }
     670             : 
     671           0 : static struct opq_client_reg *opq_client_alloc(
     672             :         const struct zapi_opaque_reg_info *info)
     673             : {
     674           0 :         struct opq_client_reg *client;
     675             : 
     676           0 :         client = XCALLOC(MTYPE_OPQ, sizeof(struct opq_client_reg));
     677             : 
     678           0 :         client->proto = info->proto;
     679           0 :         client->instance = info->instance;
     680           0 :         client->session_id = info->session_id;
     681             : 
     682           0 :         return client;
     683             : }
     684             : 
     685           0 : static void opq_client_free(struct opq_client_reg **client)
     686             : {
     687           0 :         XFREE(MTYPE_OPQ, (*client));
     688             : }
     689             : 
     690           0 : static const char *opq_client2str(char *buf, size_t buflen,
     691             :                                   const struct opq_client_reg *client)
     692             : {
     693           0 :         char sbuf[20];
     694             : 
     695           0 :         snprintf(buf, buflen, "%s/%u", zebra_route_string(client->proto),
     696           0 :                  client->instance);
     697           0 :         if (client->session_id > 0) {
     698           0 :                 snprintf(sbuf, sizeof(sbuf), "/%u", client->session_id);
     699           0 :                 strlcat(buf, sbuf, buflen);
     700             :         }
     701             : 
     702           0 :         return buf;
     703             : }
     704             : 
     705             : /* Hash function for clients registered for messages */
     706           0 : static uint32_t registration_hash(const struct opq_msg_reg *reg)
     707             : {
     708           0 :         return reg->type;
     709             : }
     710             : 
     711             : /* Comparison function for client registrations */
     712           0 : static int registration_compare(const struct opq_msg_reg *reg1,
     713             :                                 const struct opq_msg_reg *reg2)
     714             : {
     715           0 :         if (reg1->type == reg2->type)
     716             :                 return 0;
     717             :         else
     718           0 :                 return -1;
     719             : }

Generated by: LCOV version v1.16-topotato