LCOV - code coverage report
Current view: top level - spdk/module/bdev/nvme - bdev_mdns_client.c (source / functions) Hit Total Coverage
Test: Combined Lines: 213 307 69.4 %
Date: 2024-11-15 12:27:34 Functions: 18 18 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 119 221 53.8 %

           Branch data     Line data    Source code
       1                 :            : /*  SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *  Copyright (c) 2022 Dell Inc, or its subsidiaries.
       3                 :            :  *  All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/version.h"
       8                 :            : 
       9                 :            : #include "spdk_internal/event.h"
      10                 :            : 
      11                 :            : #include "spdk/assert.h"
      12                 :            : #include "spdk/config.h"
      13                 :            : #include "spdk/env.h"
      14                 :            : #include "spdk/init.h"
      15                 :            : #include "spdk/log.h"
      16                 :            : #include "spdk/thread.h"
      17                 :            : #include "spdk/trace.h"
      18                 :            : #include "spdk/string.h"
      19                 :            : #include "spdk/scheduler.h"
      20                 :            : #include "spdk/rpc.h"
      21                 :            : #include "spdk/util.h"
      22                 :            : #include "spdk/nvme.h"
      23                 :            : #include "spdk/module/bdev/nvme.h"
      24                 :            : #include "bdev_nvme.h"
      25                 :            : 
      26                 :            : #ifdef SPDK_CONFIG_AVAHI
      27                 :            : #include <avahi-client/client.h>
      28                 :            : #include <avahi-client/lookup.h>
      29                 :            : #include <avahi-common/simple-watch.h>
      30                 :            : #include <avahi-common/malloc.h>
      31                 :            : #include <avahi-common/error.h>
      32                 :            : 
      33                 :            : static AvahiSimplePoll *g_avahi_simple_poll = NULL;
      34                 :            : static AvahiClient *g_avahi_client = NULL;
      35                 :            : 
      36                 :            : struct mdns_discovery_entry_ctx {
      37                 :            :         char                                            name[256];
      38                 :            :         struct spdk_nvme_transport_id                   trid;
      39                 :            :         struct spdk_nvme_ctrlr_opts                     drv_opts;
      40                 :            :         TAILQ_ENTRY(mdns_discovery_entry_ctx)           tailq;
      41                 :            :         struct mdns_discovery_ctx                       *ctx;
      42                 :            : };
      43                 :            : 
      44                 :            : struct mdns_discovery_ctx {
      45                 :            :         char                                    *name;
      46                 :            :         char                                    *svcname;
      47                 :            :         char                                    *hostnqn;
      48                 :            :         AvahiServiceBrowser                     *sb;
      49                 :            :         struct spdk_poller                      *poller;
      50                 :            :         struct spdk_nvme_ctrlr_opts             drv_opts;
      51                 :            :         struct spdk_bdev_nvme_ctrlr_opts        bdev_opts;
      52                 :            :         uint32_t                                seqno;
      53                 :            :         bool                                    stop;
      54                 :            :         struct spdk_thread                      *calling_thread;
      55                 :            :         TAILQ_ENTRY(mdns_discovery_ctx)         tailq;
      56                 :            :         TAILQ_HEAD(, mdns_discovery_entry_ctx)  mdns_discovery_entry_ctxs;
      57                 :            : };
      58                 :            : 
      59                 :            : TAILQ_HEAD(mdns_discovery_ctxs, mdns_discovery_ctx);
      60                 :            : static struct mdns_discovery_ctxs g_mdns_discovery_ctxs = TAILQ_HEAD_INITIALIZER(
      61                 :            :                         g_mdns_discovery_ctxs);
      62                 :            : 
      63                 :            : static struct mdns_discovery_entry_ctx *
      64                 :          4 : create_mdns_discovery_entry_ctx(struct mdns_discovery_ctx *ctx, struct spdk_nvme_transport_id *trid)
      65                 :            : {
      66                 :            :         struct mdns_discovery_entry_ctx *new_ctx;
      67                 :            : 
      68         [ -  + ]:          4 :         assert(ctx);
      69         [ -  + ]:          4 :         assert(trid);
      70                 :          4 :         new_ctx = calloc(1, sizeof(*new_ctx));
      71         [ -  + ]:          4 :         if (new_ctx == NULL) {
      72                 :          0 :                 SPDK_ERRLOG("could not allocate new mdns_entry_ctx\n");
      73                 :          0 :                 return NULL;
      74                 :            :         }
      75                 :            : 
      76                 :          4 :         new_ctx->ctx = ctx;
      77   [ -  +  -  + ]:          4 :         memcpy(&new_ctx->trid, trid, sizeof(struct spdk_nvme_transport_id));
      78         [ -  + ]:          4 :         snprintf(new_ctx->name, sizeof(new_ctx->name), "%s%u_nvme", ctx->name, ctx->seqno);
      79   [ -  +  -  + ]:          4 :         memcpy(&new_ctx->drv_opts, &ctx->drv_opts, sizeof(ctx->drv_opts));
      80         [ -  + ]:          4 :         snprintf(new_ctx->drv_opts.hostnqn, sizeof(ctx->drv_opts.hostnqn), "%s", ctx->hostnqn);
      81                 :          4 :         ctx->seqno = ctx->seqno + 1;
      82                 :          4 :         return new_ctx;
      83                 :            : }
      84                 :            : 
      85                 :            : static void
      86                 :          4 : mdns_bdev_nvme_start_discovery(void *_entry_ctx)
      87                 :            : {
      88                 :            :         int status;
      89                 :          4 :         struct mdns_discovery_entry_ctx *entry_ctx = _entry_ctx;
      90                 :            : 
      91         [ -  + ]:          4 :         assert(_entry_ctx);
      92                 :          8 :         status = bdev_nvme_start_discovery(&entry_ctx->trid, entry_ctx->name,
      93                 :          4 :                                            &entry_ctx->ctx->drv_opts,
      94                 :          4 :                                            &entry_ctx->ctx->bdev_opts,
      95                 :            :                                            0, true, NULL, NULL);
      96         [ -  + ]:          4 :         if (status) {
      97                 :          0 :                 SPDK_ERRLOG("Error starting discovery for name %s addr %s port %s subnqn %s &trid %p\n",
      98                 :            :                             entry_ctx->ctx->name, entry_ctx->trid.traddr, entry_ctx->trid.trsvcid,
      99                 :            :                             entry_ctx->trid.subnqn, &entry_ctx->trid);
     100                 :            :         }
     101                 :          4 : }
     102                 :            : 
     103                 :            : static void
     104                 :          2 : free_mdns_discovery_entry_ctx(struct mdns_discovery_ctx *ctx)
     105                 :            : {
     106                 :            :         struct mdns_discovery_entry_ctx *entry_ctx, *tmp;
     107                 :            : 
     108         [ -  + ]:          2 :         if (!ctx) {
     109                 :          0 :                 return;
     110                 :            :         }
     111                 :            : 
     112         [ +  + ]:          6 :         TAILQ_FOREACH_SAFE(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq, tmp) {
     113         [ +  + ]:          4 :                 TAILQ_REMOVE(&ctx->mdns_discovery_entry_ctxs, entry_ctx, tailq);
     114                 :          4 :                 free(entry_ctx);
     115                 :            :         }
     116                 :            : }
     117                 :            : 
     118                 :            : static void
     119                 :          2 : free_mdns_discovery_ctx(struct mdns_discovery_ctx *ctx)
     120                 :            : {
     121         [ -  + ]:          2 :         if (!ctx) {
     122                 :          0 :                 return;
     123                 :            :         }
     124                 :            : 
     125                 :          2 :         free(ctx->name);
     126                 :          2 :         free(ctx->svcname);
     127                 :          2 :         free(ctx->hostnqn);
     128                 :          2 :         avahi_service_browser_free(ctx->sb);
     129                 :          2 :         free_mdns_discovery_entry_ctx(ctx);
     130                 :          2 :         free(ctx);
     131                 :            : }
     132                 :            : 
     133                 :            : /* get_key_val_avahi_resolve_txt - Search for the key string in the TXT received
     134                 :            :  *                            from Avavi daemon and return its value.
     135                 :            :  *   input
     136                 :            :  *       txt: TXT returned by Ahavi daemon will be of format
     137                 :            :  *            "NQN=nqn.1988-11.com.dell:SFSS:1:20221122170722e8" "p=tcp foo" and the
     138                 :            :  *            AvahiStringList txt is a linked list with each node holding a
     139                 :            :  *            key-value pair like key:p value:tcp
     140                 :            :  *
     141                 :            :  *       key: Key string to search in the txt list
     142                 :            :  *   output
     143                 :            :  *       Returns the value for the key or NULL if key is not present
     144                 :            :  *       Returned string needs to be freed with avahi_free()
     145                 :            :  */
     146                 :            : static char *
     147                 :         16 : get_key_val_avahi_resolve_txt(AvahiStringList *txt, const char *key)
     148                 :            : {
     149                 :         16 :         char *k = NULL, *v = NULL;
     150                 :         16 :         AvahiStringList *p = NULL;
     151                 :            :         int r;
     152                 :            : 
     153   [ +  -  -  + ]:         16 :         if (!txt || !key) {
     154                 :          0 :                 return NULL;
     155                 :            :         }
     156                 :            : 
     157                 :         16 :         p = avahi_string_list_find(txt, key);
     158         [ -  + ]:         16 :         if (!p) {
     159                 :          0 :                 return NULL;
     160                 :            :         }
     161                 :            : 
     162                 :         16 :         r = avahi_string_list_get_pair(p, &k, &v, NULL);
     163         [ -  + ]:         16 :         if (r < 0) {
     164                 :          0 :                 return NULL;
     165                 :            :         }
     166                 :            : 
     167                 :         16 :         avahi_free(k);
     168                 :         16 :         return v;
     169                 :            : }
     170                 :            : 
     171                 :            : static int
     172                 :          8 : get_spdk_nvme_transport_from_proto_str(char *protocol, enum spdk_nvme_transport_type *trtype)
     173                 :            : {
     174                 :          8 :         int status = -1;
     175                 :            : 
     176   [ +  -  -  + ]:          8 :         if (!protocol || !trtype) {
     177                 :          0 :                 return status;
     178                 :            :         }
     179                 :            : 
     180   [ -  +  +  - ]:          8 :         if (strcmp("tcp", protocol) == 0) {
     181                 :          8 :                 *trtype = SPDK_NVME_TRANSPORT_TCP;
     182                 :          8 :                 return 0;
     183                 :            :         }
     184                 :            : 
     185                 :          0 :         return status;
     186                 :            : }
     187                 :            : 
     188                 :            : static enum spdk_nvmf_adrfam
     189                 :          8 : get_spdk_nvme_adrfam_from_avahi_addr(const AvahiAddress *address) {
     190                 :            : 
     191         [ -  + ]:          8 :         if (!address)
     192                 :            :         {
     193                 :            :                 /* Return ipv4 by default */
     194                 :          0 :                 return SPDK_NVMF_ADRFAM_IPV4;
     195                 :            :         }
     196                 :            : 
     197      [ +  -  - ]:          8 :         switch (address->proto)
     198                 :            :         {
     199                 :          8 :         case AVAHI_PROTO_INET:
     200                 :          8 :                 return SPDK_NVMF_ADRFAM_IPV4;
     201                 :          0 :         case AVAHI_PROTO_INET6:
     202                 :          0 :                 return SPDK_NVMF_ADRFAM_IPV6;
     203                 :          0 :         default:
     204                 :          0 :                 return SPDK_NVMF_ADRFAM_IPV4;
     205                 :            :         }
     206                 :            : }
     207                 :            : 
     208                 :            : static struct mdns_discovery_ctx *
     209                 :          8 : get_mdns_discovery_ctx_by_svcname(const char *svcname)
     210                 :            : {
     211                 :          8 :         struct mdns_discovery_ctx *ctx = NULL, *tmp_ctx = NULL;
     212                 :            : 
     213         [ -  + ]:          8 :         if (!svcname) {
     214                 :          0 :                 return NULL;
     215                 :            :         }
     216                 :            : 
     217         [ +  - ]:          8 :         TAILQ_FOREACH_SAFE(ctx, &g_mdns_discovery_ctxs, tailq, tmp_ctx) {
     218   [ -  +  -  +  :          8 :                 if (strcmp(ctx->svcname, svcname) == 0) {
                   +  - ]
     219                 :          8 :                         return ctx;
     220                 :            :                 }
     221                 :            :         }
     222                 :          0 :         return NULL;
     223                 :            : }
     224                 :            : 
     225                 :            : static void
     226                 :          8 : mdns_resolve_handler(
     227                 :            :         AvahiServiceResolver *resolver,
     228                 :            :         AVAHI_GCC_UNUSED AvahiIfIndex intf,
     229                 :            :         AVAHI_GCC_UNUSED AvahiProtocol avahi_protocol,
     230                 :            :         AvahiResolverEvent resolve_event,
     231                 :            :         const char *svc_name,
     232                 :            :         const char *svc_type,
     233                 :            :         const char *svc_domain,
     234                 :            :         const char *host_name,
     235                 :            :         const AvahiAddress *host_address,
     236                 :            :         uint16_t port,
     237                 :            :         AvahiStringList *txt,
     238                 :            :         AvahiLookupResultFlags result_flags,
     239                 :            :         AVAHI_GCC_UNUSED void *user_data)
     240                 :            : {
     241         [ -  + ]:          8 :         assert(resolver);
     242                 :            :         /* The handler gets called whenever a service has been resolved
     243                 :            :            successfully or timed out */
     244      [ +  -  - ]:          8 :         switch (resolve_event) {
     245                 :          8 :         case AVAHI_RESOLVER_FOUND: {
     246                 :            :                 char ipaddr[SPDK_NVMF_TRADDR_MAX_LEN + 1], port_str[SPDK_NVMF_TRSVCID_MAX_LEN + 1], *str;
     247                 :          8 :                 struct spdk_nvme_transport_id *trid = NULL;
     248                 :          8 :                 char *subnqn = NULL, *proto = NULL;
     249                 :          8 :                 struct mdns_discovery_ctx *ctx = NULL;
     250                 :          8 :                 struct mdns_discovery_entry_ctx *entry_ctx = NULL;
     251                 :          8 :                 int status = -1;
     252                 :            : 
     253         [ -  + ]:          8 :                 memset(ipaddr, 0, sizeof(ipaddr));
     254         [ -  + ]:          8 :                 memset(port_str, 0, sizeof(port_str));
     255   [ -  +  +  - ]:          8 :                 SPDK_INFOLOG(bdev_nvme, "Service '%s' of type '%s' in domain '%s'\n", svc_name, svc_type,
     256                 :            :                              svc_domain);
     257                 :          8 :                 avahi_address_snprint(ipaddr, sizeof(ipaddr), host_address);
     258         [ -  + ]:          8 :                 snprintf(port_str, sizeof(port_str), "%d", port);
     259                 :          8 :                 str = avahi_string_list_to_string(txt);
     260   [ -  +  +  - ]:          8 :                 SPDK_INFOLOG(bdev_nvme,
     261                 :            :                              "\t%s:%u (%s)\n"
     262                 :            :                              "\tTXT=%s\n"
     263                 :            :                              "\tcookie is %u\n"
     264                 :            :                              "\tis_local: %i\n"
     265                 :            :                              "\tour_own: %i\n"
     266                 :            :                              "\twide_area: %i\n"
     267                 :            :                              "\tmulticast: %i\n"
     268                 :            :                              "\tcached: %i\n",
     269                 :            :                              host_name, port, ipaddr,
     270                 :            :                              str,
     271                 :            :                              avahi_string_list_get_service_cookie(txt),
     272                 :            :                              !!(result_flags & AVAHI_LOOKUP_RESULT_LOCAL),
     273                 :            :                              !!(result_flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
     274                 :            :                              !!(result_flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
     275                 :            :                              !!(result_flags & AVAHI_LOOKUP_RESULT_MULTICAST),
     276                 :            :                              !!(result_flags & AVAHI_LOOKUP_RESULT_CACHED));
     277                 :          8 :                 avahi_free(str);
     278                 :            : 
     279                 :          8 :                 ctx = get_mdns_discovery_ctx_by_svcname(svc_type);
     280         [ -  + ]:          8 :                 if (!ctx) {
     281                 :          0 :                         SPDK_ERRLOG("Unknown Service '%s'\n", svc_type);
     282                 :          4 :                         break;
     283                 :            :                 }
     284                 :            : 
     285                 :          8 :                 trid = (struct spdk_nvme_transport_id *) calloc(1, sizeof(struct spdk_nvme_transport_id));
     286         [ -  + ]:          8 :                 if (!trid) {
     287                 :          0 :                         SPDK_ERRLOG(" Error allocating memory for trid\n");
     288                 :          0 :                         break;
     289                 :            :                 }
     290                 :          8 :                 trid->adrfam = get_spdk_nvme_adrfam_from_avahi_addr(host_address);
     291         [ -  + ]:          8 :                 if (trid->adrfam != SPDK_NVMF_ADRFAM_IPV4) {
     292                 :            :                         /* TODO: For now process only ipv4 addresses */
     293   [ #  #  #  # ]:          0 :                         SPDK_INFOLOG(bdev_nvme, "trid family is not IPV4 %d\n", trid->adrfam);
     294                 :          0 :                         free(trid);
     295                 :          0 :                         break;
     296                 :            :                 }
     297                 :          8 :                 subnqn = get_key_val_avahi_resolve_txt(txt, "NQN");
     298         [ -  + ]:          8 :                 if (!subnqn) {
     299                 :          0 :                         free(trid);
     300                 :          0 :                         SPDK_ERRLOG("subnqn received is empty for service %s\n", ctx->svcname);
     301                 :          0 :                         break;
     302                 :            :                 }
     303                 :          8 :                 proto = get_key_val_avahi_resolve_txt(txt, "p");
     304         [ -  + ]:          8 :                 if (!proto) {
     305                 :          0 :                         free(trid);
     306                 :          0 :                         avahi_free(subnqn);
     307                 :          0 :                         SPDK_ERRLOG("Protocol not received for service %s\n", ctx->svcname);
     308                 :          0 :                         break;
     309                 :            :                 }
     310                 :          8 :                 status = get_spdk_nvme_transport_from_proto_str(proto, &trid->trtype);
     311         [ -  + ]:          8 :                 if (status) {
     312                 :          0 :                         free(trid);
     313                 :          0 :                         avahi_free(subnqn);
     314                 :          0 :                         avahi_free(proto);
     315                 :          0 :                         SPDK_ERRLOG("Unable to derive nvme transport type  for service %s\n", ctx->svcname);
     316                 :          0 :                         break;
     317                 :            :                 }
     318         [ -  + ]:          8 :                 snprintf(trid->traddr, sizeof(trid->traddr), "%s", ipaddr);
     319         [ -  + ]:          8 :                 snprintf(trid->trsvcid, sizeof(trid->trsvcid), "%s", port_str);
     320         [ -  + ]:          8 :                 snprintf(trid->subnqn, sizeof(trid->subnqn), "%s", subnqn);
     321         [ +  + ]:         12 :                 TAILQ_FOREACH(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq) {
     322         [ +  + ]:          8 :                         if (!spdk_nvme_transport_id_compare(trid, &entry_ctx->trid)) {
     323                 :          4 :                                 SPDK_ERRLOG("mDNS discovery entry exists already. trid->traddr: %s trid->trsvcid: %s\n",
     324                 :            :                                             trid->traddr, trid->trsvcid);
     325                 :          4 :                                 free(trid);
     326                 :          4 :                                 avahi_free(subnqn);
     327                 :          4 :                                 avahi_free(proto);
     328                 :          4 :                                 avahi_service_resolver_free(resolver);
     329                 :          4 :                                 return;
     330                 :            :                         }
     331                 :            :                 }
     332                 :          4 :                 entry_ctx = create_mdns_discovery_entry_ctx(ctx, trid);
     333                 :          4 :                 TAILQ_INSERT_TAIL(&ctx->mdns_discovery_entry_ctxs, entry_ctx, tailq);
     334                 :          4 :                 spdk_thread_send_msg(ctx->calling_thread, mdns_bdev_nvme_start_discovery, entry_ctx);
     335                 :          4 :                 free(trid);
     336                 :          4 :                 avahi_free(subnqn);
     337                 :          4 :                 avahi_free(proto);
     338                 :          4 :                 break;
     339                 :            :         }
     340                 :          0 :         case AVAHI_RESOLVER_FAILURE:
     341                 :          0 :                 SPDK_ERRLOG("(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n",
     342                 :            :                             svc_name, svc_type, svc_domain,
     343                 :            :                             avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))));
     344                 :          0 :                 break;
     345                 :          0 :         default:
     346                 :          0 :                 SPDK_ERRLOG("Unknown Avahi resolver event: %d", resolve_event);
     347                 :            :         }
     348                 :          4 :         avahi_service_resolver_free(resolver);
     349                 :            : }
     350                 :            : 
     351                 :            : static void
     352                 :         12 : mdns_browse_handler(
     353                 :            :         AvahiServiceBrowser *browser,
     354                 :            :         AvahiIfIndex intf,
     355                 :            :         AvahiProtocol avahi_protocol,
     356                 :            :         AvahiBrowserEvent browser_event,
     357                 :            :         const char *svc_name,
     358                 :            :         const char *svc_type,
     359                 :            :         const char *svc_domain,
     360                 :            :         AVAHI_GCC_UNUSED AvahiLookupResultFlags result_flags,
     361                 :            :         void *user_data)
     362                 :            : {
     363                 :         12 :         AvahiClient *client = user_data;
     364                 :            : 
     365         [ -  + ]:         12 :         assert(browser);
     366                 :            :         /* The handler gets called whenever a new service becomes available
     367                 :            :            or removed from the LAN */
     368   [ +  -  +  -  :         12 :         switch (browser_event) {
                      - ]
     369                 :          8 :         case AVAHI_BROWSER_NEW:
     370   [ -  +  +  - ]:          8 :                 SPDK_DEBUGLOG(bdev_nvme, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", svc_name,
     371                 :            :                               svc_type,
     372                 :            :                               svc_domain);
     373                 :            :                 /* We ignore the returned resolver object. In the callback
     374                 :            :                    function we free it. If the server is terminated before
     375                 :            :                    the callback function is called the server will free
     376                 :            :                    the resolver for us. */
     377         [ -  + ]:          8 :                 if (!(avahi_service_resolver_new(client, intf, avahi_protocol, svc_name, svc_type, svc_domain,
     378                 :            :                                                  AVAHI_PROTO_UNSPEC, 0,
     379                 :            :                                                  mdns_resolve_handler, client))) {
     380                 :          0 :                         SPDK_ERRLOG("Failed to resolve service '%s': %s\n", svc_name,
     381                 :            :                                     avahi_strerror(avahi_client_errno(client)));
     382                 :            :                 }
     383                 :          8 :                 break;
     384                 :          0 :         case AVAHI_BROWSER_REMOVE:
     385                 :          0 :                 SPDK_ERRLOG("(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", svc_name, svc_type,
     386                 :            :                             svc_domain);
     387                 :            :                 /* On remove, we are not doing the automatic cleanup of connections
     388                 :            :                  * to the targets that were learnt from the CDC, for which remove event has
     389                 :            :                  * been received. If required, user can clear the connections manually by
     390                 :            :                  * invoking bdev_nvme_stop_discovery. We can implement the automatic cleanup
     391                 :            :                  * later, if there is a requirement in the future.
     392                 :            :                  */
     393                 :          0 :                 break;
     394                 :          4 :         case AVAHI_BROWSER_ALL_FOR_NOW:
     395                 :            :         case AVAHI_BROWSER_CACHE_EXHAUSTED:
     396   [ -  +  +  -  :          4 :                 SPDK_INFOLOG(bdev_nvme, "(Browser) %s\n",
                   +  + ]
     397                 :            :                              browser_event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
     398                 :          4 :                 break;
     399                 :          0 :         case AVAHI_BROWSER_FAILURE:
     400                 :          0 :                 SPDK_ERRLOG("(Browser) Failure: %s\n",
     401                 :            :                             avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(browser))));
     402                 :          0 :                 return;
     403                 :          0 :         default:
     404                 :          0 :                 SPDK_ERRLOG("Unknown Avahi browser event: %d", browser_event);
     405                 :            :         }
     406                 :            : }
     407                 :            : 
     408                 :            : static void
     409                 :          1 : client_handler(AvahiClient *client, AvahiClientState avahi_state, AVAHI_GCC_UNUSED void *user_data)
     410                 :            : {
     411         [ -  + ]:          1 :         assert(client);
     412                 :            :         /* The handler gets called whenever the client or server state changes */
     413         [ -  + ]:          1 :         if (avahi_state == AVAHI_CLIENT_FAILURE) {
     414                 :          0 :                 SPDK_ERRLOG("Server connection failure: %s\n", avahi_strerror(avahi_client_errno(client)));
     415                 :            :         }
     416                 :          1 : }
     417                 :            : 
     418                 :            : static int
     419                 :        161 : bdev_nvme_avahi_iterate(void *arg)
     420                 :            : {
     421                 :        161 :         struct mdns_discovery_ctx *ctx = arg;
     422                 :            :         int rc;
     423                 :            : 
     424   [ -  +  +  + ]:        161 :         if (ctx->stop) {
     425   [ -  +  +  - ]:          2 :                 SPDK_INFOLOG(bdev_nvme, "Stopping avahi poller for service %s\n", ctx->svcname);
     426                 :          2 :                 spdk_poller_unregister(&ctx->poller);
     427         [ -  + ]:          2 :                 TAILQ_REMOVE(&g_mdns_discovery_ctxs, ctx, tailq);
     428                 :          2 :                 free_mdns_discovery_ctx(ctx);
     429                 :          2 :                 return SPDK_POLLER_IDLE;
     430                 :            :         }
     431                 :            : 
     432         [ -  + ]:        159 :         if (g_avahi_simple_poll == NULL) {
     433                 :          0 :                 spdk_poller_unregister(&ctx->poller);
     434                 :          0 :                 return SPDK_POLLER_IDLE;
     435                 :            :         }
     436                 :            : 
     437                 :        159 :         rc = avahi_simple_poll_iterate(g_avahi_simple_poll, 0);
     438   [ -  +  -  - ]:        159 :         if (rc && rc != -EAGAIN) {
     439                 :          0 :                 SPDK_ERRLOG("avahi poll returned error for service: %s/n", ctx->svcname);
     440                 :          0 :                 return SPDK_POLLER_IDLE;
     441                 :            :         }
     442                 :            : 
     443                 :        159 :         return SPDK_POLLER_BUSY;
     444                 :            : }
     445                 :            : 
     446                 :            : static void
     447                 :          2 : start_mdns_discovery_poller(void *arg)
     448                 :            : {
     449                 :          2 :         struct mdns_discovery_ctx *ctx = arg;
     450                 :            : 
     451         [ -  + ]:          2 :         assert(arg);
     452                 :          2 :         TAILQ_INSERT_TAIL(&g_mdns_discovery_ctxs, ctx, tailq);
     453                 :          2 :         ctx->poller = SPDK_POLLER_REGISTER(bdev_nvme_avahi_iterate, ctx, 100 * 1000);
     454                 :          2 : }
     455                 :            : 
     456                 :            : int
     457                 :          4 : bdev_nvme_start_mdns_discovery(const char *base_name,
     458                 :            :                                const char *svcname,
     459                 :            :                                struct spdk_nvme_ctrlr_opts *drv_opts,
     460                 :            :                                struct spdk_bdev_nvme_ctrlr_opts *bdev_opts)
     461                 :            : {
     462                 :          4 :         AvahiServiceBrowser *sb = NULL;
     463                 :            :         int error;
     464                 :            :         struct mdns_discovery_ctx *ctx;
     465                 :            : 
     466         [ -  + ]:          4 :         assert(base_name);
     467         [ -  + ]:          4 :         assert(svcname);
     468                 :            : 
     469         [ +  + ]:          4 :         TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
     470   [ -  +  -  +  :          2 :                 if (strcmp(ctx->name, base_name) == 0) {
                   +  + ]
     471                 :          1 :                         SPDK_ERRLOG("mDNS discovery already running with name %s\n", base_name);
     472                 :          1 :                         return -EEXIST;
     473                 :            :                 }
     474                 :            : 
     475   [ -  +  -  +  :          1 :                 if (strcmp(ctx->svcname, svcname) == 0) {
                   +  - ]
     476                 :          1 :                         SPDK_ERRLOG("mDNS discovery already running for service %s\n", svcname);
     477                 :          1 :                         return -EEXIST;
     478                 :            :                 }
     479                 :            :         }
     480                 :            : 
     481         [ +  + ]:          2 :         if (g_avahi_simple_poll == NULL) {
     482                 :            : 
     483                 :            :                 /* Allocate main loop object */
     484         [ -  + ]:          1 :                 if (!(g_avahi_simple_poll = avahi_simple_poll_new())) {
     485                 :          0 :                         SPDK_ERRLOG("Failed to create poll object for mDNS discovery for service: %s.\n", svcname);
     486                 :          0 :                         return -ENOMEM;
     487                 :            :                 }
     488                 :            :         }
     489                 :            : 
     490         [ +  + ]:          2 :         if (g_avahi_client == NULL) {
     491                 :            : 
     492                 :            :                 /* Allocate a new client */
     493                 :          1 :                 g_avahi_client = avahi_client_new(avahi_simple_poll_get(g_avahi_simple_poll), 0, client_handler,
     494                 :            :                                                   NULL, &error);
     495                 :            :                 /* Check whether creating the client object succeeded */
     496         [ -  + ]:          1 :                 if (!g_avahi_client) {
     497                 :          0 :                         SPDK_ERRLOG("Failed to create mDNS client for service:%s Error: %s\n", svcname,
     498                 :            :                                     avahi_strerror(error));
     499                 :          0 :                         return -ENOMEM;
     500                 :            :                 }
     501                 :            :         }
     502                 :            : 
     503                 :            :         /* Create the service browser */
     504         [ -  + ]:          2 :         if (!(sb = avahi_service_browser_new(g_avahi_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, svcname,
     505                 :            :                                              NULL, 0, mdns_browse_handler, g_avahi_client))) {
     506                 :          0 :                 SPDK_ERRLOG("Failed to create service browser for service: %s Error: %s\n", svcname,
     507                 :            :                             avahi_strerror(avahi_client_errno(g_avahi_client)));
     508                 :          0 :                 return -ENOMEM;
     509                 :            :         }
     510                 :            : 
     511                 :          2 :         ctx = calloc(1, sizeof(*ctx));
     512         [ -  + ]:          2 :         if (ctx == NULL) {
     513                 :          0 :                 SPDK_ERRLOG("Error creating mDNS discovery ctx for service: %s\n", svcname);
     514                 :          0 :                 avahi_service_browser_free(sb);
     515                 :          0 :                 return -ENOMEM;
     516                 :            :         }
     517                 :            : 
     518         [ -  + ]:          2 :         ctx->svcname = strdup(svcname);
     519         [ -  + ]:          2 :         if (ctx->svcname == NULL) {
     520                 :          0 :                 SPDK_ERRLOG("Error creating mDNS discovery ctx svcname for service: %s\n", svcname);
     521                 :          0 :                 free_mdns_discovery_ctx(ctx);
     522                 :          0 :                 avahi_service_browser_free(sb);
     523                 :          0 :                 return -ENOMEM;
     524                 :            :         }
     525         [ -  + ]:          2 :         ctx->name = strdup(base_name);
     526         [ -  + ]:          2 :         if (ctx->name == NULL) {
     527                 :          0 :                 SPDK_ERRLOG("Error creating mDNS discovery ctx name for service: %s\n", svcname);
     528                 :          0 :                 free_mdns_discovery_ctx(ctx);
     529                 :          0 :                 avahi_service_browser_free(sb);
     530                 :          0 :                 return -ENOMEM;
     531                 :            :         }
     532   [ -  +  -  + ]:          2 :         memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts));
     533   [ -  +  -  + ]:          2 :         memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts));
     534                 :          2 :         ctx->sb = sb;
     535                 :          2 :         ctx->calling_thread = spdk_get_thread();
     536                 :          2 :         TAILQ_INIT(&ctx->mdns_discovery_entry_ctxs);
     537                 :            :         /* Even if user did not specify hostnqn, we can still strdup("\0"); */
     538         [ -  + ]:          2 :         ctx->hostnqn = strdup(ctx->drv_opts.hostnqn);
     539         [ -  + ]:          2 :         if (ctx->hostnqn == NULL) {
     540                 :          0 :                 SPDK_ERRLOG("Error creating mDNS discovery ctx hostnqn for service: %s\n", svcname);
     541                 :          0 :                 free_mdns_discovery_ctx(ctx);
     542                 :          0 :                 return -ENOMEM;
     543                 :            :         }
     544                 :            :         /* Start the poller for the Avahi client browser in g_bdev_nvme_init_thread */
     545                 :          2 :         spdk_thread_send_msg(g_bdev_nvme_init_thread, start_mdns_discovery_poller, ctx);
     546                 :          2 :         return 0;
     547                 :            : }
     548                 :            : 
     549                 :            : static void
     550                 :          2 : mdns_stop_discovery_entry(struct mdns_discovery_ctx *ctx)
     551                 :            : {
     552                 :          2 :         struct mdns_discovery_entry_ctx *entry_ctx = NULL;
     553                 :            : 
     554         [ -  + ]:          2 :         assert(ctx);
     555                 :            : 
     556         [ +  + ]:          6 :         TAILQ_FOREACH(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq) {
     557                 :          4 :                 bdev_nvme_stop_discovery(entry_ctx->name, NULL, NULL);
     558                 :            :         }
     559                 :          2 : }
     560                 :            : 
     561                 :            : int
     562                 :          2 : bdev_nvme_stop_mdns_discovery(const char *name)
     563                 :            : {
     564                 :            :         struct mdns_discovery_ctx *ctx;
     565                 :            : 
     566         [ -  + ]:          2 :         assert(name);
     567         [ +  - ]:          2 :         TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
     568   [ -  +  -  +  :          2 :                 if (strcmp(name, ctx->name) == 0) {
                   +  - ]
     569   [ -  +  -  + ]:          2 :                         if (ctx->stop) {
     570                 :          0 :                                 return -EALREADY;
     571                 :            :                         }
     572                 :            :                         /* set stop to true to stop the mdns poller instance */
     573                 :          2 :                         ctx->stop = true;
     574                 :          2 :                         mdns_stop_discovery_entry(ctx);
     575                 :          2 :                         return 0;
     576                 :            :                 }
     577                 :            :         }
     578                 :            : 
     579                 :          0 :         return -ENOENT;
     580                 :            : }
     581                 :            : 
     582                 :            : void
     583                 :          3 : bdev_nvme_get_mdns_discovery_info(struct spdk_jsonrpc_request *request)
     584                 :            : {
     585                 :            :         struct mdns_discovery_ctx *ctx;
     586                 :            :         struct mdns_discovery_entry_ctx *entry_ctx;
     587                 :            :         struct spdk_json_write_ctx *w;
     588                 :            : 
     589                 :          3 :         w = spdk_jsonrpc_begin_result(request);
     590                 :          3 :         spdk_json_write_array_begin(w);
     591         [ +  + ]:          5 :         TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
     592                 :          2 :                 spdk_json_write_object_begin(w);
     593                 :          2 :                 spdk_json_write_named_string(w, "name", ctx->name);
     594                 :          2 :                 spdk_json_write_named_string(w, "svcname", ctx->svcname);
     595                 :            : 
     596                 :          2 :                 spdk_json_write_named_array_begin(w, "referrals");
     597         [ +  + ]:          6 :                 TAILQ_FOREACH(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq) {
     598                 :          4 :                         spdk_json_write_object_begin(w);
     599                 :          4 :                         spdk_json_write_named_string(w, "name", entry_ctx->name);
     600                 :          4 :                         spdk_json_write_named_object_begin(w, "trid");
     601                 :          4 :                         nvme_bdev_dump_trid_json(&entry_ctx->trid, w);
     602                 :          4 :                         spdk_json_write_object_end(w);
     603                 :          4 :                         spdk_json_write_object_end(w);
     604                 :            :                 }
     605                 :          2 :                 spdk_json_write_array_end(w);
     606                 :            : 
     607                 :          2 :                 spdk_json_write_object_end(w);
     608                 :            :         }
     609                 :          3 :         spdk_json_write_array_end(w);
     610                 :          3 :         spdk_jsonrpc_end_result(request, w);
     611                 :          3 : }
     612                 :            : 
     613                 :            : void
     614                 :         12 : bdev_nvme_mdns_discovery_config_json(struct spdk_json_write_ctx *w)
     615                 :            : {
     616                 :            :         struct mdns_discovery_ctx *ctx;
     617                 :            : 
     618         [ -  + ]:         12 :         TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
     619                 :          0 :                 spdk_json_write_object_begin(w);
     620                 :            : 
     621                 :          0 :                 spdk_json_write_named_string(w, "method", "bdev_nvme_start_mdns_discovery");
     622                 :            : 
     623                 :          0 :                 spdk_json_write_named_object_begin(w, "params");
     624                 :          0 :                 spdk_json_write_named_string(w, "name", ctx->name);
     625                 :          0 :                 spdk_json_write_named_string(w, "svcname", ctx->svcname);
     626                 :          0 :                 spdk_json_write_named_string(w, "hostnqn", ctx->hostnqn);
     627                 :          0 :                 spdk_json_write_object_end(w);
     628                 :            : 
     629                 :          0 :                 spdk_json_write_object_end(w);
     630                 :            :         }
     631                 :         12 : }
     632                 :            : 
     633                 :            : #else /* SPDK_CONFIG_AVAHI */
     634                 :            : 
     635                 :            : int
     636                 :          0 : bdev_nvme_start_mdns_discovery(const char *base_name,
     637                 :            :                                const char *svcname,
     638                 :            :                                struct spdk_nvme_ctrlr_opts *drv_opts,
     639                 :            :                                struct spdk_bdev_nvme_ctrlr_opts *bdev_opts)
     640                 :            : {
     641                 :          0 :         SPDK_ERRLOG("spdk not built with --with-avahi option\n");
     642                 :          0 :         return -ENOTSUP;
     643                 :            : }
     644                 :            : 
     645                 :            : int
     646                 :          0 : bdev_nvme_stop_mdns_discovery(const char *name)
     647                 :            : {
     648                 :          0 :         SPDK_ERRLOG("spdk not built with --with-avahi option\n");
     649                 :          0 :         return -ENOTSUP;
     650                 :            : }
     651                 :            : 
     652                 :            : void
     653                 :          0 : bdev_nvme_get_mdns_discovery_info(struct spdk_jsonrpc_request *request)
     654                 :            : {
     655                 :          0 :         SPDK_ERRLOG("spdk not built with --with-avahi option\n");
     656                 :          0 :         spdk_jsonrpc_send_error_response(request, -ENOTSUP, spdk_strerror(ENOTSUP));
     657                 :          0 : }
     658                 :            : 
     659                 :            : void
     660                 :        161 : bdev_nvme_mdns_discovery_config_json(struct spdk_json_write_ctx *w)
     661                 :            : {
     662                 :            :         /* Empty function to be invoked, when SPDK is built without --with-avahi */
     663                 :        161 : }
     664                 :            : 
     665                 :            : #endif

Generated by: LCOV version 1.14