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 "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 : 150 : 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 : 150 : }
663 : :
664 : : #endif
|