LCOV - code coverage report
Current view: top level - lib/iscsi - portal_grp.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 163 300 54.3 %
Date: 2024-12-06 08:19:16 Functions: 15 27 55.6 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
       3             :  *   Copyright (C) 2016 Intel Corporation.
       4             :  *   All rights reserved.
       5             :  */
       6             : 
       7             : #include "spdk/stdinc.h"
       8             : 
       9             : #include "spdk/sock.h"
      10             : #include "spdk/string.h"
      11             : 
      12             : #include "spdk/log.h"
      13             : 
      14             : #include "iscsi/iscsi.h"
      15             : #include "iscsi/conn.h"
      16             : #include "iscsi/portal_grp.h"
      17             : #include "iscsi/tgt_node.h"
      18             : 
      19             : #define PORTNUMSTRLEN 32
      20             : #define ACCEPT_TIMEOUT_US 1000 /* 1ms */
      21             : 
      22             : static int
      23           0 : iscsi_portal_accept(void *arg)
      24             : {
      25           0 :         struct spdk_iscsi_portal        *portal = arg;
      26           0 :         struct spdk_sock                *sock;
      27           0 :         int                             rc;
      28           0 :         int                             count = 0;
      29             : 
      30           0 :         if (portal->sock == NULL) {
      31           0 :                 return -1;
      32             :         }
      33             : 
      34           0 :         while (1) {
      35           0 :                 sock = spdk_sock_accept(portal->sock);
      36           0 :                 if (sock != NULL) {
      37           0 :                         rc = iscsi_conn_construct(portal, sock);
      38           0 :                         if (rc < 0) {
      39           0 :                                 spdk_sock_close(&sock);
      40           0 :                                 SPDK_ERRLOG("spdk_iscsi_connection_construct() failed\n");
      41           0 :                                 break;
      42             :                         }
      43           0 :                         count++;
      44           0 :                 } else {
      45           0 :                         if (errno != EAGAIN && errno != EWOULDBLOCK) {
      46           0 :                                 SPDK_ERRLOG("accept error(%d): %s\n", errno, spdk_strerror(errno));
      47           0 :                         }
      48           0 :                         break;
      49             :                 }
      50             :         }
      51             : 
      52           0 :         return count;
      53           0 : }
      54             : 
      55             : static struct spdk_iscsi_portal *
      56          11 : iscsi_portal_find_by_addr(const char *host, const char *port)
      57             : {
      58          11 :         struct spdk_iscsi_portal *p;
      59             : 
      60          12 :         TAILQ_FOREACH(p, &g_iscsi.portal_head, g_tailq) {
      61           2 :                 if (!strcmp(p->host, host) && !strcmp(p->port, port)) {
      62           1 :                         return p;
      63             :                 }
      64           1 :         }
      65             : 
      66          10 :         return NULL;
      67          11 : }
      68             : 
      69             : /* Assumes caller allocated host and port strings on the heap */
      70             : struct spdk_iscsi_portal *
      71          11 : iscsi_portal_create(const char *host, const char *port)
      72             : {
      73          11 :         struct spdk_iscsi_portal *p = NULL, *tmp;
      74             : 
      75          11 :         assert(host != NULL);
      76          11 :         assert(port != NULL);
      77             : 
      78          11 :         if (strlen(host) > MAX_PORTAL_ADDR || strlen(port) > MAX_PORTAL_PORT) {
      79           0 :                 return NULL;
      80             :         }
      81             : 
      82          11 :         p = calloc(1, sizeof(*p));
      83          11 :         if (!p) {
      84           0 :                 SPDK_ERRLOG("calloc() failed for portal\n");
      85           0 :                 return NULL;
      86             :         }
      87             : 
      88             :         /* check and overwrite abbreviation of wildcard */
      89          11 :         if (strcasecmp(host, "[*]") == 0) {
      90           1 :                 SPDK_WARNLOG("Please use \"[::]\" as IPv6 wildcard\n");
      91           1 :                 SPDK_WARNLOG("Convert \"[*]\" to \"[::]\" automatically\n");
      92           1 :                 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)");
      93           1 :                 snprintf(p->host, sizeof(p->host), "[::]");
      94          11 :         } else if (strcasecmp(host, "*") == 0) {
      95           1 :                 SPDK_WARNLOG("Please use \"0.0.0.0\" as IPv4 wildcard\n");
      96           1 :                 SPDK_WARNLOG("Convert \"*\" to \"0.0.0.0\" automatically\n");
      97           1 :                 SPDK_WARNLOG("(Use of \"[*]\" will be deprecated in a future release)");
      98           1 :                 snprintf(p->host, sizeof(p->host), "0.0.0.0");
      99           1 :         } else {
     100           9 :                 memcpy(p->host, host, strlen(host));
     101             :         }
     102             : 
     103          11 :         memcpy(p->port, port, strlen(port));
     104             : 
     105          11 :         p->sock = NULL;
     106          11 :         p->group = NULL; /* set at a later time by caller */
     107          11 :         p->acceptor_poller = NULL;
     108             : 
     109          11 :         pthread_mutex_lock(&g_iscsi.mutex);
     110          11 :         tmp = iscsi_portal_find_by_addr(host, port);
     111          11 :         if (tmp != NULL) {
     112           1 :                 pthread_mutex_unlock(&g_iscsi.mutex);
     113           1 :                 SPDK_ERRLOG("portal (%s, %s) already exists\n", host, port);
     114           1 :                 goto error_out;
     115             :         }
     116             : 
     117          10 :         TAILQ_INSERT_TAIL(&g_iscsi.portal_head, p, g_tailq);
     118          10 :         pthread_mutex_unlock(&g_iscsi.mutex);
     119             : 
     120          10 :         return p;
     121             : 
     122             : error_out:
     123           1 :         free(p);
     124             : 
     125           1 :         return NULL;
     126          11 : }
     127             : 
     128             : void
     129          10 : iscsi_portal_destroy(struct spdk_iscsi_portal *p)
     130             : {
     131          10 :         assert(p != NULL);
     132             : 
     133          10 :         SPDK_DEBUGLOG(iscsi, "iscsi_portal_destroy\n");
     134             : 
     135          10 :         pthread_mutex_lock(&g_iscsi.mutex);
     136          10 :         TAILQ_REMOVE(&g_iscsi.portal_head, p, g_tailq);
     137          10 :         pthread_mutex_unlock(&g_iscsi.mutex);
     138             : 
     139          10 :         free(p);
     140             : 
     141          10 : }
     142             : 
     143             : static int
     144           3 : iscsi_portal_open(struct spdk_iscsi_portal *p)
     145             : {
     146           3 :         struct spdk_sock *sock;
     147           3 :         int port;
     148             : 
     149           3 :         if (p->sock != NULL) {
     150           0 :                 SPDK_ERRLOG("portal (%s, %s) is already opened\n",
     151             :                             p->host, p->port);
     152           0 :                 return -1;
     153             :         }
     154             : 
     155           3 :         port = (int)strtol(p->port, NULL, 0);
     156           3 :         if (port <= 0 || port > 65535) {
     157           0 :                 SPDK_ERRLOG("invalid port %s\n", p->port);
     158           0 :                 return -1;
     159             :         }
     160             : 
     161           3 :         sock = spdk_sock_listen(p->host, port, NULL);
     162           3 :         if (sock == NULL) {
     163           0 :                 SPDK_ERRLOG("listen error %.64s.%d\n", p->host, port);
     164           0 :                 return -1;
     165             :         }
     166             : 
     167           3 :         p->sock = sock;
     168             : 
     169             :         /*
     170             :          * When the portal is created by config file, incoming connection
     171             :          * requests for the socket are pended to accept until reactors start.
     172             :          * However the gap between listen() and accept() will be slight and
     173             :          * the requests will be queued by the nonzero backlog of the socket
     174             :          * or resend by TCP.
     175             :          */
     176           3 :         p->acceptor_poller = SPDK_POLLER_REGISTER(iscsi_portal_accept, p, ACCEPT_TIMEOUT_US);
     177             : 
     178           3 :         return 0;
     179           3 : }
     180             : 
     181             : static void
     182           3 : iscsi_portal_close(struct spdk_iscsi_portal *p)
     183             : {
     184           3 :         if (p->sock) {
     185           3 :                 SPDK_DEBUGLOG(iscsi, "close portal (%s, %s)\n",
     186             :                               p->host, p->port);
     187           3 :                 spdk_poller_unregister(&p->acceptor_poller);
     188           3 :                 spdk_sock_close(&p->sock);
     189           3 :         }
     190           3 : }
     191             : 
     192             : static void
     193           0 : iscsi_portal_pause(struct spdk_iscsi_portal *p)
     194             : {
     195           0 :         assert(p->acceptor_poller != NULL);
     196             : 
     197           0 :         spdk_poller_pause(p->acceptor_poller);
     198           0 : }
     199             : 
     200             : static void
     201           0 : iscsi_portal_resume(struct spdk_iscsi_portal *p)
     202             : {
     203           0 :         assert(p->acceptor_poller != NULL);
     204             : 
     205           0 :         spdk_poller_resume(p->acceptor_poller);
     206           0 : }
     207             : 
     208             : int
     209           0 : iscsi_parse_redirect_addr(struct sockaddr_storage *sa,
     210             :                           const char *host, const char *port)
     211             : {
     212           0 :         struct addrinfo hints, *res;
     213           0 :         int rc;
     214             : 
     215           0 :         if (host == NULL || port == NULL) {
     216           0 :                 return -EINVAL;
     217             :         }
     218             : 
     219           0 :         memset(&hints, 0, sizeof(hints));
     220           0 :         hints.ai_family = PF_UNSPEC;
     221           0 :         hints.ai_socktype = SOCK_STREAM;
     222           0 :         hints.ai_flags = AI_NUMERICSERV;
     223           0 :         hints.ai_flags |= AI_NUMERICHOST;
     224           0 :         rc = getaddrinfo(host, port, &hints, &res);
     225           0 :         if (rc != 0) {
     226           0 :                 SPDK_ERRLOG("getaddinrfo failed: %s (%d)\n", gai_strerror(rc), rc);
     227           0 :                 return -(abs(rc));
     228             :         }
     229             : 
     230           0 :         if (res->ai_addrlen > sizeof(*sa)) {
     231           0 :                 SPDK_ERRLOG("getaddrinfo() ai_addrlen %zu too large\n",
     232             :                             (size_t)res->ai_addrlen);
     233           0 :                 rc = -EINVAL;
     234           0 :         } else {
     235           0 :                 memcpy(sa, res->ai_addr, res->ai_addrlen);
     236             :         }
     237             : 
     238           0 :         freeaddrinfo(res);
     239           0 :         return rc;
     240           0 : }
     241             : 
     242             : struct spdk_iscsi_portal_grp *
     243           5 : iscsi_portal_grp_create(int tag, bool is_private)
     244             : {
     245           5 :         struct spdk_iscsi_portal_grp *pg = malloc(sizeof(*pg));
     246             : 
     247           5 :         if (!pg) {
     248           0 :                 SPDK_ERRLOG("malloc() failed for portal group\n");
     249           0 :                 return NULL;
     250             :         }
     251             : 
     252           5 :         pg->ref = 0;
     253           5 :         pg->tag = tag;
     254           5 :         pg->is_private = is_private;
     255             : 
     256           5 :         pthread_mutex_lock(&g_iscsi.mutex);
     257           5 :         pg->disable_chap = g_iscsi.disable_chap;
     258           5 :         pg->require_chap = g_iscsi.require_chap;
     259           5 :         pg->mutual_chap = g_iscsi.mutual_chap;
     260           5 :         pg->chap_group = g_iscsi.chap_group;
     261           5 :         pthread_mutex_unlock(&g_iscsi.mutex);
     262             : 
     263           5 :         TAILQ_INIT(&pg->head);
     264             : 
     265           5 :         return pg;
     266           5 : }
     267             : 
     268             : void
     269           5 : iscsi_portal_grp_destroy(struct spdk_iscsi_portal_grp *pg)
     270             : {
     271           5 :         struct spdk_iscsi_portal        *p;
     272             : 
     273           5 :         assert(pg != NULL);
     274             : 
     275           5 :         SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_destroy\n");
     276          10 :         while (!TAILQ_EMPTY(&pg->head)) {
     277           5 :                 p = TAILQ_FIRST(&pg->head);
     278           5 :                 TAILQ_REMOVE(&pg->head, p, per_pg_tailq);
     279           5 :                 iscsi_portal_destroy(p);
     280             :         }
     281           5 :         free(pg);
     282           5 : }
     283             : 
     284             : int
     285           6 : iscsi_portal_grp_register(struct spdk_iscsi_portal_grp *pg)
     286             : {
     287           6 :         int rc = -1;
     288           6 :         struct spdk_iscsi_portal_grp *tmp;
     289             : 
     290           6 :         assert(pg != NULL);
     291             : 
     292           6 :         pthread_mutex_lock(&g_iscsi.mutex);
     293           6 :         tmp = iscsi_portal_grp_find_by_tag(pg->tag);
     294           6 :         if (tmp == NULL) {
     295           5 :                 TAILQ_INSERT_TAIL(&g_iscsi.pg_head, pg, tailq);
     296           5 :                 rc = 0;
     297           5 :         }
     298           6 :         pthread_mutex_unlock(&g_iscsi.mutex);
     299          12 :         return rc;
     300           6 : }
     301             : 
     302             : void
     303           5 : iscsi_portal_grp_add_portal(struct spdk_iscsi_portal_grp *pg,
     304             :                             struct spdk_iscsi_portal *p)
     305             : {
     306           5 :         assert(pg != NULL);
     307           5 :         assert(p != NULL);
     308             : 
     309           5 :         p->group = pg;
     310           5 :         TAILQ_INSERT_TAIL(&pg->head, p, per_pg_tailq);
     311           5 : }
     312             : 
     313             : struct spdk_iscsi_portal *
     314           0 : iscsi_portal_grp_find_portal_by_addr(struct spdk_iscsi_portal_grp *pg,
     315             :                                      const char *host, const char *port)
     316             : {
     317           0 :         struct spdk_iscsi_portal *p;
     318             : 
     319           0 :         TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
     320           0 :                 if (!strcmp(p->host, host) && !strcmp(p->port, port)) {
     321           0 :                         return p;
     322             :                 }
     323           0 :         }
     324             : 
     325           0 :         return NULL;
     326           0 : }
     327             : 
     328             : int
     329           0 : iscsi_portal_grp_set_chap_params(struct spdk_iscsi_portal_grp *pg,
     330             :                                  bool disable_chap, bool require_chap,
     331             :                                  bool mutual_chap, int32_t chap_group)
     332             : {
     333           0 :         if (!iscsi_check_chap_params(disable_chap, require_chap,
     334           0 :                                      mutual_chap, chap_group)) {
     335           0 :                 return -EINVAL;
     336             :         }
     337             : 
     338           0 :         pg->disable_chap = disable_chap;
     339           0 :         pg->require_chap = require_chap;
     340           0 :         pg->mutual_chap = mutual_chap;
     341           0 :         pg->chap_group = chap_group;
     342             : 
     343           0 :         return 0;
     344           0 : }
     345             : 
     346             : struct spdk_iscsi_portal_grp *
     347           6 : iscsi_portal_grp_find_by_tag(int tag)
     348             : {
     349           6 :         struct spdk_iscsi_portal_grp *pg;
     350             : 
     351           7 :         TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
     352           2 :                 if (pg->tag == tag) {
     353           1 :                         return pg;
     354             :                 }
     355           1 :         }
     356             : 
     357           5 :         return NULL;
     358           6 : }
     359             : 
     360             : void
     361           1 : iscsi_portal_grps_destroy(void)
     362             : {
     363           1 :         struct spdk_iscsi_portal_grp *pg;
     364             : 
     365           1 :         SPDK_DEBUGLOG(iscsi, "iscsi_portal_grps_destroy\n");
     366           1 :         pthread_mutex_lock(&g_iscsi.mutex);
     367           3 :         while (!TAILQ_EMPTY(&g_iscsi.pg_head)) {
     368           2 :                 pg = TAILQ_FIRST(&g_iscsi.pg_head);
     369           2 :                 TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq);
     370           2 :                 pthread_mutex_unlock(&g_iscsi.mutex);
     371           2 :                 iscsi_portal_grp_destroy(pg);
     372           2 :                 pthread_mutex_lock(&g_iscsi.mutex);
     373             :         }
     374           1 :         pthread_mutex_unlock(&g_iscsi.mutex);
     375           1 : }
     376             : 
     377             : int
     378           3 : iscsi_portal_grp_open(struct spdk_iscsi_portal_grp *pg, bool pause)
     379             : {
     380           3 :         struct spdk_iscsi_portal *p;
     381           3 :         int rc;
     382             : 
     383           6 :         TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
     384           3 :                 rc = iscsi_portal_open(p);
     385           3 :                 if (rc < 0) {
     386           0 :                         return rc;
     387             :                 }
     388             : 
     389           3 :                 if (pause) {
     390           0 :                         iscsi_portal_pause(p);
     391           0 :                 }
     392           3 :         }
     393           3 :         return 0;
     394           3 : }
     395             : 
     396             : static void
     397           3 : iscsi_portal_grp_close(struct spdk_iscsi_portal_grp *pg)
     398             : {
     399           3 :         struct spdk_iscsi_portal *p;
     400             : 
     401           6 :         TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
     402           3 :                 iscsi_portal_close(p);
     403           3 :         }
     404           3 : }
     405             : 
     406             : void
     407           0 : iscsi_portal_grp_resume(struct spdk_iscsi_portal_grp *pg)
     408             : {
     409           0 :         struct spdk_iscsi_portal *p;
     410             : 
     411           0 :         TAILQ_FOREACH(p, &pg->head, per_pg_tailq) {
     412           0 :                 iscsi_portal_resume(p);
     413           0 :         }
     414           0 : }
     415             : 
     416             : void
     417           0 : iscsi_portal_grp_close_all(void)
     418             : {
     419           0 :         struct spdk_iscsi_portal_grp *pg;
     420             : 
     421           0 :         SPDK_DEBUGLOG(iscsi, "iscsi_portal_grp_close_all\n");
     422           0 :         pthread_mutex_lock(&g_iscsi.mutex);
     423           0 :         TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
     424           0 :                 iscsi_portal_grp_close(pg);
     425           0 :         }
     426           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     427           0 : }
     428             : 
     429             : struct spdk_iscsi_portal_grp *
     430           3 : iscsi_portal_grp_unregister(int tag)
     431             : {
     432           3 :         struct spdk_iscsi_portal_grp *pg;
     433             : 
     434           3 :         pthread_mutex_lock(&g_iscsi.mutex);
     435           3 :         TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
     436           3 :                 if (pg->tag == tag) {
     437           3 :                         TAILQ_REMOVE(&g_iscsi.pg_head, pg, tailq);
     438           3 :                         pthread_mutex_unlock(&g_iscsi.mutex);
     439           3 :                         return pg;
     440             :                 }
     441           0 :         }
     442           0 :         pthread_mutex_unlock(&g_iscsi.mutex);
     443           0 :         return NULL;
     444           3 : }
     445             : 
     446             : void
     447           1 : iscsi_portal_grp_release(struct spdk_iscsi_portal_grp *pg)
     448             : {
     449           1 :         iscsi_portal_grp_close(pg);
     450           1 :         iscsi_portal_grp_destroy(pg);
     451           1 : }
     452             : 
     453             : static void
     454           0 : iscsi_portal_grp_info_json(struct spdk_iscsi_portal_grp *pg,
     455             :                            struct spdk_json_write_ctx *w)
     456             : {
     457           0 :         struct spdk_iscsi_portal *portal;
     458             : 
     459           0 :         spdk_json_write_object_begin(w);
     460             : 
     461           0 :         spdk_json_write_named_int32(w, "tag", pg->tag);
     462             : 
     463           0 :         spdk_json_write_named_array_begin(w, "portals");
     464           0 :         TAILQ_FOREACH(portal, &pg->head, per_pg_tailq) {
     465           0 :                 spdk_json_write_object_begin(w);
     466             : 
     467           0 :                 spdk_json_write_named_string(w, "host", portal->host);
     468           0 :                 spdk_json_write_named_string(w, "port", portal->port);
     469             : 
     470           0 :                 spdk_json_write_object_end(w);
     471           0 :         }
     472           0 :         spdk_json_write_array_end(w);
     473             : 
     474           0 :         spdk_json_write_named_bool(w, "private", pg->is_private);
     475             : 
     476           0 :         spdk_json_write_object_end(w);
     477           0 : }
     478             : 
     479             : static void
     480           0 : iscsi_portal_grp_config_json(struct spdk_iscsi_portal_grp *pg,
     481             :                              struct spdk_json_write_ctx *w)
     482             : {
     483           0 :         spdk_json_write_object_begin(w);
     484             : 
     485           0 :         spdk_json_write_named_string(w, "method", "iscsi_create_portal_group");
     486             : 
     487           0 :         spdk_json_write_name(w, "params");
     488           0 :         iscsi_portal_grp_info_json(pg, w);
     489             : 
     490           0 :         spdk_json_write_object_end(w);
     491           0 : }
     492             : 
     493             : void
     494           0 : iscsi_portal_grps_info_json(struct spdk_json_write_ctx *w)
     495             : {
     496           0 :         struct spdk_iscsi_portal_grp *pg;
     497             : 
     498           0 :         TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
     499           0 :                 iscsi_portal_grp_info_json(pg, w);
     500           0 :         }
     501           0 : }
     502             : 
     503             : void
     504           0 : iscsi_portal_grps_config_json(struct spdk_json_write_ctx *w)
     505             : {
     506           0 :         struct spdk_iscsi_portal_grp *pg;
     507             : 
     508           0 :         TAILQ_FOREACH(pg, &g_iscsi.pg_head, tailq) {
     509           0 :                 iscsi_portal_grp_config_json(pg, w);
     510           0 :         }
     511           0 : }

Generated by: LCOV version 1.15