Let's keep up with IET. :) = From: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx> Subject: [PATCH] iscsi: target redirect support root@rose:~# tgtadm --op update --mode target --tid 1 --name RedirectAddress --value 10.76.0.30 root@rose:~# tgtadm --op update --mode target --tid 1 --name RedirectPort --value 3260 root@rose:~# tgtadm --op update --mode target --tid 1 --name RedirectReason --value Temporary root@rose:~# tgtadm --op show --mode target --tid 1 RedirectAddress=10.76.0.30 RedirectPort=3260 RedirectReason=Temporary If you want "Target moved permanently", root@rose:~# tgtadm --op update --mode target --tid 1 --name RedirectReason --value Permanent Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx> --- usr/iscsi/iscsid.c | 12 ++++++ usr/iscsi/iscsid.h | 8 ++++ usr/iscsi/target.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 127 insertions(+), 1 deletions(-) diff --git a/usr/iscsi/iscsid.c b/usr/iscsi/iscsid.c index b4e0969..e66323c 100644 --- a/usr/iscsi/iscsid.c +++ b/usr/iscsi/iscsid.c @@ -489,8 +489,20 @@ static void login_start(struct iscsi_connection *conn) conn->state = STATE_EXIT; return; } + conn->tid = target->tid; + if (target_redirected(target, conn)) { + char buf[NI_MAXHOST + NI_MAXSERV + 4]; + snprintf(buf, sizeof(buf), "%s:%s", target->redirect_info.addr, + target->redirect_info.port); + text_key_add(conn, "TargetAddress", buf); + rsp->status_class = ISCSI_STATUS_CLS_REDIRECT; + rsp->status_detail = target->redirect_info.reason; + conn->state = STATE_EXIT; + return; + } + if (tgt_get_target_state(target->tid) != SCSI_TARGET_READY) { rsp->status_class = ISCSI_STATUS_CLS_TARGET_ERR; rsp->status_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR; diff --git a/usr/iscsi/iscsid.h b/usr/iscsi/iscsid.h index 1e70d81..7e501a4 100644 --- a/usr/iscsi/iscsid.h +++ b/usr/iscsi/iscsid.h @@ -21,6 +21,7 @@ #include <stdint.h> #include <inttypes.h> +#include <netdb.h> #include "transport.h" #include "list.h" @@ -243,6 +244,12 @@ struct iscsi_target { int max_nr_sessions; int nr_sessions; + struct redirect_info { + char addr[NI_MAXHOST + 1]; + char port[NI_MAXSERV + 1]; + uint8_t reason; + } redirect_info; + struct list_head isns_list; int efd; @@ -316,6 +323,7 @@ extern int iscsi_target_show(int mode, int tid, uint64_t sid, uint32_t cid, uint64_t lun, char *buf, int rest); int iscsi_target_update(int mode, int op, int tid, uint64_t sid, uint64_t lun, uint32_t cid, char *name); +int target_redirected(struct iscsi_target *target, struct iscsi_connection *conn); int iscsi_pthread_per_target(void); diff --git a/usr/iscsi/target.c b/usr/iscsi/target.c index b547626..c86d851 100644 --- a/usr/iscsi/target.c +++ b/usr/iscsi/target.c @@ -192,6 +192,55 @@ int ip_acl(int tid, struct iscsi_connection *conn) return -EPERM; } +int target_redirected(struct iscsi_target *target, struct iscsi_connection *conn) +{ + struct sockaddr_storage from; + struct addrinfo hints, *res; + socklen_t len; + int ret; + char *p, *q, *str; + + if (!strlen(target->redirect_info.addr)) + return 0; + + if (target->redirect_info.reason != ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP && + target->redirect_info.reason != ISCSI_LOGIN_STATUS_TGT_MOVED_PERM) + return 0; + + len = sizeof(from); + ret = conn->tp->ep_getpeername(conn, (struct sockaddr *)&from, &len); + if (ret < 0) + return 0; + + p = strdup(target->redirect_info.addr); + if (!p) + return 0; + str = p; + + if (*p == '[') { + p++; + if (!(q = strchr(p, ']'))) + return 0; + *(q++) = '\0'; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + + ret = getaddrinfo(p, NULL, &hints, &res); + if (ret < 0) { + free(str); + return 0; + } + + ret = address_match(res->ai_addr, (struct sockaddr *)&from); + freeaddrinfo(res); + free(str); + + return !ret; +} + void target_list_build(struct iscsi_connection *conn, char *addr, char *name) { struct iscsi_target *target; @@ -416,6 +465,29 @@ int iscsi_target_update(int mode, int op, int tid, uint64_t sid, uint64_t lun, dprintf("%s:%s\n", name, str); + if (!strncmp(name, "RedirectAddress", 15)) { + snprintf(target->redirect_info.addr, + sizeof(target->redirect_info.addr), "%s", str); + err = TGTADM_SUCCESS; + break; + } else if (!strncmp(name, "RedirectPort", 12)) { + snprintf(target->redirect_info.port, + sizeof(target->redirect_info.port), "%s", str); + err = TGTADM_SUCCESS; + break; + } else if (!strncmp(name, "RedirectReason", 14)) { + if (!strncmp(str, "Temporary", 9)) { + target->redirect_info.reason = + ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP; + err = TGTADM_SUCCESS; + } else if (!strncmp(str, "Permanent", 9)) { + target->redirect_info.reason = + ISCSI_LOGIN_STATUS_TGT_MOVED_PERM; + err = TGTADM_SUCCESS; + } else + break; + } + idx = param_index_by_name(name, session_keys); if (idx >= 0) { err = iscsi_session_param_update(target, idx, str); @@ -463,6 +535,37 @@ static int iscsi_target_show_session(struct iscsi_target* target, uint64_t sid, return total; } +#define __buffer_check(buf, total, len, rest) \ +({ \ + buf += len; \ + total += len; \ + rest -= len; \ + if (!rest) \ + return total; \ +}) + +static int show_redirect_info(struct iscsi_target* target, char *buf, int rest) +{ + int len, total = 0; + + len = snprintf(buf, rest, "RedirectAddress=%s\n", target->redirect_info.addr); + __buffer_check(buf, total, len, rest); + len = snprintf(buf, rest, "RedirectPort=%s\n", target->redirect_info.port); + __buffer_check(buf, total, len, rest); + if (target->redirect_info.reason == ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP) { + len = snprintf(buf, rest, "RedirectReason=Temporary\n"); + __buffer_check(buf, total, len, rest); + } else if (target->redirect_info.reason == ISCSI_LOGIN_STATUS_TGT_MOVED_PERM) { + len = snprintf(buf, rest, "RedirectReason=Permanent\n"); + __buffer_check(buf, total, len, rest); + } else { + len = snprintf(buf, rest, "RedirectReason=Unknown\n"); + __buffer_check(buf, total, len, rest); + } + + return total; +} + int iscsi_target_show(int mode, int tid, uint64_t sid, uint32_t cid, uint64_t lun, char *buf, int rest) { @@ -480,7 +583,10 @@ int iscsi_target_show(int mode, int tid, uint64_t sid, uint32_t cid, uint64_t lu total = isns_show(buf, rest); break; case MODE_TARGET: - len = show_iscsi_param(buf, target->session_param, rest); + if (strlen(target->redirect_info.addr)) + len = show_redirect_info(target, buf, rest); + else + len = show_iscsi_param(buf, target->session_param, rest); total += len; break; case MODE_SESSION: -- 1.6.5 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html