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 : 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 : assert(ctx);
69 : assert(trid);
70 : new_ctx = calloc(1, sizeof(*new_ctx));
71 : if (new_ctx == NULL) {
72 : SPDK_ERRLOG("could not allocate new mdns_entry_ctx\n");
73 : return NULL;
74 : }
75 :
76 : new_ctx->ctx = ctx;
77 : memcpy(&new_ctx->trid, trid, sizeof(struct spdk_nvme_transport_id));
78 : snprintf(new_ctx->name, sizeof(new_ctx->name), "%s%u_nvme", ctx->name, ctx->seqno);
79 : memcpy(&new_ctx->drv_opts, &ctx->drv_opts, sizeof(ctx->drv_opts));
80 : snprintf(new_ctx->drv_opts.hostnqn, sizeof(ctx->drv_opts.hostnqn), "%s", ctx->hostnqn);
81 : ctx->seqno = ctx->seqno + 1;
82 : return new_ctx;
83 : }
84 :
85 : static void
86 : mdns_bdev_nvme_start_discovery(void *_entry_ctx)
87 : {
88 : int status;
89 : struct mdns_discovery_entry_ctx *entry_ctx = _entry_ctx;
90 :
91 : assert(_entry_ctx);
92 : status = bdev_nvme_start_discovery(&entry_ctx->trid, entry_ctx->name,
93 : &entry_ctx->ctx->drv_opts,
94 : &entry_ctx->ctx->bdev_opts,
95 : 0, true, NULL, NULL);
96 : if (status) {
97 : 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 : }
102 :
103 : static void
104 : free_mdns_discovery_entry_ctx(struct mdns_discovery_ctx *ctx)
105 : {
106 : struct mdns_discovery_entry_ctx *entry_ctx, *tmp;
107 :
108 : if (!ctx) {
109 : return;
110 : }
111 :
112 : TAILQ_FOREACH_SAFE(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq, tmp) {
113 : TAILQ_REMOVE(&ctx->mdns_discovery_entry_ctxs, entry_ctx, tailq);
114 : free(entry_ctx);
115 : }
116 : }
117 :
118 : static void
119 : free_mdns_discovery_ctx(struct mdns_discovery_ctx *ctx)
120 : {
121 : if (!ctx) {
122 : return;
123 : }
124 :
125 : free(ctx->name);
126 : free(ctx->svcname);
127 : free(ctx->hostnqn);
128 : avahi_service_browser_free(ctx->sb);
129 : free_mdns_discovery_entry_ctx(ctx);
130 : 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 : get_key_val_avahi_resolve_txt(AvahiStringList *txt, const char *key)
148 : {
149 : char *k = NULL, *v = NULL;
150 : AvahiStringList *p = NULL;
151 : int r;
152 :
153 : if (!txt || !key) {
154 : return NULL;
155 : }
156 :
157 : p = avahi_string_list_find(txt, key);
158 : if (!p) {
159 : return NULL;
160 : }
161 :
162 : r = avahi_string_list_get_pair(p, &k, &v, NULL);
163 : if (r < 0) {
164 : return NULL;
165 : }
166 :
167 : avahi_free(k);
168 : return v;
169 : }
170 :
171 : static int
172 : get_spdk_nvme_transport_from_proto_str(char *protocol, enum spdk_nvme_transport_type *trtype)
173 : {
174 : int status = -1;
175 :
176 : if (!protocol || !trtype) {
177 : return status;
178 : }
179 :
180 : if (strcmp("tcp", protocol) == 0) {
181 : *trtype = SPDK_NVME_TRANSPORT_TCP;
182 : return 0;
183 : }
184 :
185 : return status;
186 : }
187 :
188 : static enum spdk_nvmf_adrfam
189 : get_spdk_nvme_adrfam_from_avahi_addr(const AvahiAddress *address) {
190 :
191 : if (!address)
192 : {
193 : /* Return ipv4 by default */
194 : return SPDK_NVMF_ADRFAM_IPV4;
195 : }
196 :
197 : switch (address->proto)
198 : {
199 : case AVAHI_PROTO_INET:
200 : return SPDK_NVMF_ADRFAM_IPV4;
201 : case AVAHI_PROTO_INET6:
202 : return SPDK_NVMF_ADRFAM_IPV6;
203 : default:
204 : return SPDK_NVMF_ADRFAM_IPV4;
205 : }
206 : }
207 :
208 : static struct mdns_discovery_ctx *
209 : get_mdns_discovery_ctx_by_svcname(const char *svcname)
210 : {
211 : struct mdns_discovery_ctx *ctx = NULL, *tmp_ctx = NULL;
212 :
213 : if (!svcname) {
214 : return NULL;
215 : }
216 :
217 : TAILQ_FOREACH_SAFE(ctx, &g_mdns_discovery_ctxs, tailq, tmp_ctx) {
218 : if (strcmp(ctx->svcname, svcname) == 0) {
219 : return ctx;
220 : }
221 : }
222 : return NULL;
223 : }
224 :
225 : static void
226 : 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 : assert(resolver);
242 : /* The handler gets called whenever a service has been resolved
243 : successfully or timed out */
244 : switch (resolve_event) {
245 : case AVAHI_RESOLVER_FOUND: {
246 : char ipaddr[SPDK_NVMF_TRADDR_MAX_LEN + 1], port_str[SPDK_NVMF_TRSVCID_MAX_LEN + 1], *str;
247 : struct spdk_nvme_transport_id *trid = NULL;
248 : char *subnqn = NULL, *proto = NULL;
249 : struct mdns_discovery_ctx *ctx = NULL;
250 : struct mdns_discovery_entry_ctx *entry_ctx = NULL;
251 : int status = -1;
252 :
253 : memset(ipaddr, 0, sizeof(ipaddr));
254 : memset(port_str, 0, sizeof(port_str));
255 : SPDK_INFOLOG(bdev_nvme, "Service '%s' of type '%s' in domain '%s'\n", svc_name, svc_type,
256 : svc_domain);
257 : avahi_address_snprint(ipaddr, sizeof(ipaddr), host_address);
258 : snprintf(port_str, sizeof(port_str), "%d", port);
259 : str = avahi_string_list_to_string(txt);
260 : 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 : avahi_free(str);
278 :
279 : ctx = get_mdns_discovery_ctx_by_svcname(svc_type);
280 : if (!ctx) {
281 : SPDK_ERRLOG("Unknown Service '%s'\n", svc_type);
282 : break;
283 : }
284 :
285 : trid = (struct spdk_nvme_transport_id *) calloc(1, sizeof(struct spdk_nvme_transport_id));
286 : if (!trid) {
287 : SPDK_ERRLOG(" Error allocating memory for trid\n");
288 : break;
289 : }
290 : trid->adrfam = get_spdk_nvme_adrfam_from_avahi_addr(host_address);
291 : if (trid->adrfam != SPDK_NVMF_ADRFAM_IPV4) {
292 : /* TODO: For now process only ipv4 addresses */
293 : SPDK_INFOLOG(bdev_nvme, "trid family is not IPV4 %d\n", trid->adrfam);
294 : free(trid);
295 : break;
296 : }
297 : subnqn = get_key_val_avahi_resolve_txt(txt, "NQN");
298 : if (!subnqn) {
299 : free(trid);
300 : SPDK_ERRLOG("subnqn received is empty for service %s\n", ctx->svcname);
301 : break;
302 : }
303 : proto = get_key_val_avahi_resolve_txt(txt, "p");
304 : if (!proto) {
305 : free(trid);
306 : avahi_free(subnqn);
307 : SPDK_ERRLOG("Protocol not received for service %s\n", ctx->svcname);
308 : break;
309 : }
310 : status = get_spdk_nvme_transport_from_proto_str(proto, &trid->trtype);
311 : if (status) {
312 : free(trid);
313 : avahi_free(subnqn);
314 : avahi_free(proto);
315 : SPDK_ERRLOG("Unable to derive nvme transport type for service %s\n", ctx->svcname);
316 : break;
317 : }
318 : snprintf(trid->traddr, sizeof(trid->traddr), "%s", ipaddr);
319 : snprintf(trid->trsvcid, sizeof(trid->trsvcid), "%s", port_str);
320 : snprintf(trid->subnqn, sizeof(trid->subnqn), "%s", subnqn);
321 : TAILQ_FOREACH(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq) {
322 : if (!spdk_nvme_transport_id_compare(trid, &entry_ctx->trid)) {
323 : SPDK_ERRLOG("mDNS discovery entry exists already. trid->traddr: %s trid->trsvcid: %s\n",
324 : trid->traddr, trid->trsvcid);
325 : free(trid);
326 : avahi_free(subnqn);
327 : avahi_free(proto);
328 : avahi_service_resolver_free(resolver);
329 : return;
330 : }
331 : }
332 : entry_ctx = create_mdns_discovery_entry_ctx(ctx, trid);
333 : TAILQ_INSERT_TAIL(&ctx->mdns_discovery_entry_ctxs, entry_ctx, tailq);
334 : spdk_thread_send_msg(ctx->calling_thread, mdns_bdev_nvme_start_discovery, entry_ctx);
335 : free(trid);
336 : avahi_free(subnqn);
337 : avahi_free(proto);
338 : break;
339 : }
340 : case AVAHI_RESOLVER_FAILURE:
341 : 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 : break;
345 : default:
346 : SPDK_ERRLOG("Unknown Avahi resolver event: %d", resolve_event);
347 : }
348 : avahi_service_resolver_free(resolver);
349 : }
350 :
351 : static void
352 : 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 : AvahiClient *client = user_data;
364 :
365 : assert(browser);
366 : /* The handler gets called whenever a new service becomes available
367 : or removed from the LAN */
368 : switch (browser_event) {
369 : case AVAHI_BROWSER_NEW:
370 : 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 : 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 : SPDK_ERRLOG("Failed to resolve service '%s': %s\n", svc_name,
381 : avahi_strerror(avahi_client_errno(client)));
382 : }
383 : break;
384 : case AVAHI_BROWSER_REMOVE:
385 : 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 : break;
394 : case AVAHI_BROWSER_ALL_FOR_NOW:
395 : case AVAHI_BROWSER_CACHE_EXHAUSTED:
396 : SPDK_INFOLOG(bdev_nvme, "(Browser) %s\n",
397 : browser_event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
398 : break;
399 : case AVAHI_BROWSER_FAILURE:
400 : SPDK_ERRLOG("(Browser) Failure: %s\n",
401 : avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(browser))));
402 : return;
403 : default:
404 : SPDK_ERRLOG("Unknown Avahi browser event: %d", browser_event);
405 : }
406 : }
407 :
408 : static void
409 : client_handler(AvahiClient *client, AvahiClientState avahi_state, AVAHI_GCC_UNUSED void *user_data)
410 : {
411 : assert(client);
412 : /* The handler gets called whenever the client or server state changes */
413 : if (avahi_state == AVAHI_CLIENT_FAILURE) {
414 : SPDK_ERRLOG("Server connection failure: %s\n", avahi_strerror(avahi_client_errno(client)));
415 : }
416 : }
417 :
418 : static int
419 : bdev_nvme_avahi_iterate(void *arg)
420 : {
421 : struct mdns_discovery_ctx *ctx = arg;
422 : int rc;
423 :
424 : if (ctx->stop) {
425 : SPDK_INFOLOG(bdev_nvme, "Stopping avahi poller for service %s\n", ctx->svcname);
426 : spdk_poller_unregister(&ctx->poller);
427 : TAILQ_REMOVE(&g_mdns_discovery_ctxs, ctx, tailq);
428 : free_mdns_discovery_ctx(ctx);
429 : return SPDK_POLLER_IDLE;
430 : }
431 :
432 : if (g_avahi_simple_poll == NULL) {
433 : spdk_poller_unregister(&ctx->poller);
434 : return SPDK_POLLER_IDLE;
435 : }
436 :
437 : rc = avahi_simple_poll_iterate(g_avahi_simple_poll, 0);
438 : if (rc && rc != -EAGAIN) {
439 : SPDK_ERRLOG("avahi poll returned error for service: %s/n", ctx->svcname);
440 : return SPDK_POLLER_IDLE;
441 : }
442 :
443 : return SPDK_POLLER_BUSY;
444 : }
445 :
446 : static void
447 : start_mdns_discovery_poller(void *arg)
448 : {
449 : struct mdns_discovery_ctx *ctx = arg;
450 :
451 : assert(arg);
452 : TAILQ_INSERT_TAIL(&g_mdns_discovery_ctxs, ctx, tailq);
453 : ctx->poller = SPDK_POLLER_REGISTER(bdev_nvme_avahi_iterate, ctx, 100 * 1000);
454 : }
455 :
456 : int
457 : 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 : AvahiServiceBrowser *sb = NULL;
463 : int error;
464 : struct mdns_discovery_ctx *ctx;
465 :
466 : assert(base_name);
467 : assert(svcname);
468 :
469 : TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
470 : if (strcmp(ctx->name, base_name) == 0) {
471 : SPDK_ERRLOG("mDNS discovery already running with name %s\n", base_name);
472 : return -EEXIST;
473 : }
474 :
475 : if (strcmp(ctx->svcname, svcname) == 0) {
476 : SPDK_ERRLOG("mDNS discovery already running for service %s\n", svcname);
477 : return -EEXIST;
478 : }
479 : }
480 :
481 : if (g_avahi_simple_poll == NULL) {
482 :
483 : /* Allocate main loop object */
484 : if (!(g_avahi_simple_poll = avahi_simple_poll_new())) {
485 : SPDK_ERRLOG("Failed to create poll object for mDNS discovery for service: %s.\n", svcname);
486 : return -ENOMEM;
487 : }
488 : }
489 :
490 : if (g_avahi_client == NULL) {
491 :
492 : /* Allocate a new client */
493 : 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 : if (!g_avahi_client) {
497 : SPDK_ERRLOG("Failed to create mDNS client for service:%s Error: %s\n", svcname,
498 : avahi_strerror(error));
499 : return -ENOMEM;
500 : }
501 : }
502 :
503 : /* Create the service browser */
504 : 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 : SPDK_ERRLOG("Failed to create service browser for service: %s Error: %s\n", svcname,
507 : avahi_strerror(avahi_client_errno(g_avahi_client)));
508 : return -ENOMEM;
509 : }
510 :
511 : ctx = calloc(1, sizeof(*ctx));
512 : if (ctx == NULL) {
513 : SPDK_ERRLOG("Error creating mDNS discovery ctx for service: %s\n", svcname);
514 : avahi_service_browser_free(sb);
515 : return -ENOMEM;
516 : }
517 :
518 : ctx->svcname = strdup(svcname);
519 : if (ctx->svcname == NULL) {
520 : SPDK_ERRLOG("Error creating mDNS discovery ctx svcname for service: %s\n", svcname);
521 : free_mdns_discovery_ctx(ctx);
522 : avahi_service_browser_free(sb);
523 : return -ENOMEM;
524 : }
525 : ctx->name = strdup(base_name);
526 : if (ctx->name == NULL) {
527 : SPDK_ERRLOG("Error creating mDNS discovery ctx name for service: %s\n", svcname);
528 : free_mdns_discovery_ctx(ctx);
529 : avahi_service_browser_free(sb);
530 : return -ENOMEM;
531 : }
532 : memcpy(&ctx->drv_opts, drv_opts, sizeof(*drv_opts));
533 : memcpy(&ctx->bdev_opts, bdev_opts, sizeof(*bdev_opts));
534 : ctx->sb = sb;
535 : ctx->calling_thread = spdk_get_thread();
536 : TAILQ_INIT(&ctx->mdns_discovery_entry_ctxs);
537 : /* Even if user did not specify hostnqn, we can still strdup("\0"); */
538 : ctx->hostnqn = strdup(ctx->drv_opts.hostnqn);
539 : if (ctx->hostnqn == NULL) {
540 : SPDK_ERRLOG("Error creating mDNS discovery ctx hostnqn for service: %s\n", svcname);
541 : free_mdns_discovery_ctx(ctx);
542 : return -ENOMEM;
543 : }
544 : /* Start the poller for the Avahi client browser in g_bdev_nvme_init_thread */
545 : spdk_thread_send_msg(g_bdev_nvme_init_thread, start_mdns_discovery_poller, ctx);
546 : return 0;
547 : }
548 :
549 : static void
550 : mdns_stop_discovery_entry(struct mdns_discovery_ctx *ctx)
551 : {
552 : struct mdns_discovery_entry_ctx *entry_ctx = NULL;
553 :
554 : assert(ctx);
555 :
556 : TAILQ_FOREACH(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq) {
557 : bdev_nvme_stop_discovery(entry_ctx->name, NULL, NULL);
558 : }
559 : }
560 :
561 : int
562 : bdev_nvme_stop_mdns_discovery(const char *name)
563 : {
564 : struct mdns_discovery_ctx *ctx;
565 :
566 : assert(name);
567 : TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
568 : if (strcmp(name, ctx->name) == 0) {
569 : if (ctx->stop) {
570 : return -EALREADY;
571 : }
572 : /* set stop to true to stop the mdns poller instance */
573 : ctx->stop = true;
574 : mdns_stop_discovery_entry(ctx);
575 : return 0;
576 : }
577 : }
578 :
579 : return -ENOENT;
580 : }
581 :
582 : void
583 : 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 : w = spdk_jsonrpc_begin_result(request);
590 : spdk_json_write_array_begin(w);
591 : TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
592 : spdk_json_write_object_begin(w);
593 : spdk_json_write_named_string(w, "name", ctx->name);
594 : spdk_json_write_named_string(w, "svcname", ctx->svcname);
595 :
596 : spdk_json_write_named_array_begin(w, "referrals");
597 : TAILQ_FOREACH(entry_ctx, &ctx->mdns_discovery_entry_ctxs, tailq) {
598 : spdk_json_write_object_begin(w);
599 : spdk_json_write_named_string(w, "name", entry_ctx->name);
600 : spdk_json_write_named_object_begin(w, "trid");
601 : nvme_bdev_dump_trid_json(&entry_ctx->trid, w);
602 : spdk_json_write_object_end(w);
603 : spdk_json_write_object_end(w);
604 : }
605 : spdk_json_write_array_end(w);
606 :
607 : spdk_json_write_object_end(w);
608 : }
609 : spdk_json_write_array_end(w);
610 : spdk_jsonrpc_end_result(request, w);
611 : }
612 :
613 : void
614 : bdev_nvme_mdns_discovery_config_json(struct spdk_json_write_ctx *w)
615 : {
616 : struct mdns_discovery_ctx *ctx;
617 :
618 : TAILQ_FOREACH(ctx, &g_mdns_discovery_ctxs, tailq) {
619 : spdk_json_write_object_begin(w);
620 :
621 : spdk_json_write_named_string(w, "method", "bdev_nvme_start_mdns_discovery");
622 :
623 : spdk_json_write_named_object_begin(w, "params");
624 : spdk_json_write_named_string(w, "name", ctx->name);
625 : spdk_json_write_named_string(w, "svcname", ctx->svcname);
626 : spdk_json_write_named_string(w, "hostnqn", ctx->hostnqn);
627 : spdk_json_write_object_end(w);
628 :
629 : spdk_json_write_object_end(w);
630 : }
631 : }
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 0 : 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 0 : }
664 :
665 : #endif
|