LCOV - code coverage report
Current view: top level - module/bdev/nvme - bdev_mdns_client.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 12 0.0 %
Date: 2024-07-13 13:18:46 Functions: 0 4 0.0 %

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

Generated by: LCOV version 1.15