From c03bd27bca17907c74838946c2b1651c5b013ec6 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 28 Jan 2014 04:19:27 +0000 Subject: [PATCH] [PATCH 7/9] iscsid: Implement iser support Add iser character device handling for accepting and handling connections received through RDMA transport. Add isert_listener device to the poll() loop and handle incoming connection requests. Differentiate between iser and non iser connections Validate RDMAExtension field and reject it if found in iscsi login request. Also, disable immediate data and first burst for iSER since it is not supported yet Signed-off-by: Yan Burman git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5235 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/include/iscsi_scst.h | 7 ++ iscsi-scst/kernel/iscsi.h | 3 + iscsi-scst/kernel/param.c | 20 ++++- iscsi-scst/usr/iscsi_scstd.c | 148 ++++++++++++++++++++++++++++++++ iscsi-scst/usr/iscsid.c | 29 +++++++ iscsi-scst/usr/iscsid.h | 7 ++ iscsi-scst/usr/param.c | 8 ++ iscsi-scst/usr/target.c | 3 +- 8 files changed, 222 insertions(+), 3 deletions(-) diff --git a/iscsi-scst/include/iscsi_scst.h b/iscsi-scst/include/iscsi_scst.h index f147db601..ce9db09d1 100644 --- a/iscsi-scst/include/iscsi_scst.h +++ b/iscsi-scst/include/iscsi_scst.h @@ -62,6 +62,13 @@ enum { key_ifmarker, key_ofmarkint, key_ifmarkint, + key_rdma_extensions, + key_target_recv_data_length, + key_initiator_recv_data_length, + key_max_ahs_length, + key_tagged_buffer_for_solicited_data_only, + key_iser_hello_required, + key_max_outstanding_unexpected_pdus, session_key_last, }; diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index f5593320c..ec05699da 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -59,6 +59,9 @@ struct iscsi_sess_params { int ifmarker; int ofmarkint; int ifmarkint; + int rdma_extensions; + int target_recv_data_length; + int initiator_recv_data_length; }; struct iscsi_tgt_params { diff --git a/iscsi-scst/kernel/param.c b/iscsi-scst/kernel/param.c index aaa476010..4a5936365 100644 --- a/iscsi-scst/kernel/param.c +++ b/iscsi-scst/kernel/param.c @@ -99,12 +99,13 @@ static void log_params(struct iscsi_sess_params *params) iscsi_get_bool_value(params->data_sequence_inorder), params->error_recovery_level); PRINT_INFO(" HeaderDigest %s, DataDigest %s, OFMarker %s, " - "IFMarker %s, OFMarkInt %d, IFMarkInt %d", + "IFMarker %s, OFMarkInt %d, IFMarkInt %d, RDMAExtensions %s", iscsi_get_digest_name(params->header_digest, hdigest_name), iscsi_get_digest_name(params->data_digest, ddigest_name), iscsi_get_bool_value(params->ofmarker), iscsi_get_bool_value(params->ifmarker), - params->ofmarkint, params->ifmarkint); + params->ofmarkint, params->ifmarkint, + iscsi_get_bool_value(params->rdma_extensions)); } /* target_mutex supposed to be locked */ @@ -136,6 +137,11 @@ static void sess_params_check(struct iscsi_kern_params_info *info) CHECK_PARAM(info, iparams, ofmarker, 0, 0); CHECK_PARAM(info, iparams, ifmarker, 0, 0); + /* iSER related parameters */ + CHECK_PARAM(info, iparams, rdma_extensions, 0, 1); + CHECK_PARAM(info, iparams, target_recv_data_length, 512, max_len); + CHECK_PARAM(info, iparams, initiator_recv_data_length, 512, max_len); + return; } @@ -164,6 +170,11 @@ static void sess_params_set(struct iscsi_sess_params *params, SET_PARAM(params, info, iparams, ifmarker); SET_PARAM(params, info, iparams, ofmarkint); SET_PARAM(params, info, iparams, ifmarkint); + + /* iSER related parameters */ + SET_PARAM(params, info, iparams, rdma_extensions); + SET_PARAM(params, info, iparams, target_recv_data_length); + SET_PARAM(params, info, iparams, initiator_recv_data_length); return; } @@ -191,6 +202,11 @@ static void sess_params_get(struct iscsi_sess_params *params, GET_PARAM(params, info, iparams, ifmarker); GET_PARAM(params, info, iparams, ofmarkint); GET_PARAM(params, info, iparams, ifmarkint); + + /* iSER related parameters */ + GET_PARAM(params, info, iparams, rdma_extensions); + GET_PARAM(params, info, iparams, target_recv_data_length); + GET_PARAM(params, info, iparams, initiator_recv_data_length); return; } diff --git a/iscsi-scst/usr/iscsi_scstd.c b/iscsi-scst/usr/iscsi_scstd.c index 00a03355c..94e13d3a8 100644 --- a/iscsi-scst/usr/iscsi_scstd.c +++ b/iscsi-scst/usr/iscsi_scstd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -199,16 +200,157 @@ static struct connection *alloc_and_init_conn(int fd) pollfd->events = POLLIN; pollfd->revents = 0; + conn_read_pdu(conn); + set_non_blocking(fd); + out: return conn; } +static int transmit_iser(int fd, bool start) +{ + int opt = start; + return ioctl(fd, RDMA_CORK, &opt, sizeof(opt)); +} + +static void create_iser_listen_socket(struct pollfd *array) +{ + struct addrinfo hints, *res, *res0; + char servname[64]; + int rc, i; + int iser_fd; + struct isert_addr_info info; + + iser_fd = create_and_open_dev("isert_scst", 1); + + poll_array[POLL_ISER_LISTEN].fd = iser_fd; + if (iser_fd != -1) { + poll_array[POLL_ISER_LISTEN].events = POLLIN; + + /* RDMAExtensions */ + session_keys[key_rdma_extensions].max = 1; + session_keys[key_rdma_extensions].local_def = 1; + } else { + poll_array[POLL_ISER_LISTEN].events = 0; + return; + } + + memset(servname, 0, sizeof(servname)); + snprintf(servname, sizeof(servname), "%d", server_port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + rc = getaddrinfo(server_address, servname, &hints, &res0); + if (rc != 0) { + log_error("Unable to get address info (%s)!", + get_error_str(rc)); + exit(1); + } + + i = 0; + for (res = res0; res && i < ISERT_MAX_PORTALS; res = res->ai_next) { + memcpy(&info.addr, res->ai_addr, res->ai_addrlen); + info.addr_len = res->ai_addrlen; + + rc = ioctl(iser_fd, SET_LISTEN_ADDR, &info); + if (rc != 0) { + log_error("Unable to set address info (%s)!", + strerror(rc)); + } + ++i; + } + + freeaddrinfo(res0); +} + +static int iser_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) +{ + struct isert_addr_info addr; + int ret; + + ret = ioctl(fd, GET_PORTAL_ADDR, &addr, sizeof(addr)); + if (ret) + return ret; + + memcpy(name, &addr.addr, addr.addr_len); + *namelen = addr.addr_len; + + return ret; +} + +static int iser_is_discovery(int fd) +{ + int val = 1; + + return ioctl(fd, DISCOVERY_SESSION, &val, sizeof(val)); +} + +static void iser_accept(int fd) +{ + char buff[256]; + int ret, conn_fd; + struct connection *conn; + char target_portal[ISCSI_PORTAL_LEN], target_portal_port[NI_MAXSERV]; + struct isert_addr_info addr; + + ret = read(fd, buff, sizeof(buff)); + if (ret == -1) + return; + + conn_fd = open(buff, O_RDWR); + if (conn_fd == -1) { + log_error("open(iser_connection) %s failed: %s\n", + buff, strerror(errno)); + return; + } + + ret = ioctl(conn_fd, GET_PORTAL_ADDR, &addr, sizeof(addr)); + if (ret) + return; + + ret = getnameinfo((struct sockaddr *)&addr, sizeof(addr), target_portal, + sizeof(target_portal), target_portal_port, + sizeof(target_portal_port), + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret != 0) { + log_error("Target portal getnameinfo() failed: %s!", + get_error_str(ret)); + return; + } + + conn = alloc_and_init_conn(conn_fd); + if (!conn) + return; + + conn->target_portal = strdup(target_portal); + if (conn->target_portal == NULL) { + log_error("Unable to duplicate target portal %s", target_portal); + conn_free(conn); + return; + } + + conn->transmit = transmit_iser; + conn->getsockname = iser_getsockname; + conn->is_discovery = iser_is_discovery; + conn->is_iser = true; + incoming_cnt++; + + log_info("iSER connect\n"); +} + static int transmit_sock(int fd, bool start) { int opt = start; return setsockopt(fd, SOL_TCP, TCP_CORK, &opt, sizeof(opt)); } +static int tcp_is_discovery(int fd) +{ + return 0; +} + static void accept_connection(int listen) { union { @@ -288,6 +430,8 @@ static void accept_connection(int listen) } conn->transmit = transmit_sock; + conn->getsockname = getsockname; + conn->is_discovery = tcp_is_discovery; conn_read_pdu(conn); set_non_blocking(fd); @@ -469,6 +613,7 @@ static void event_loop(void) int res, i; create_listen_socket(poll_array + POLL_LISTEN); + create_iser_listen_socket(poll_array); poll_array[POLL_IPC].fd = ipc_fd; poll_array[POLL_IPC].events = POLLIN; @@ -542,6 +687,9 @@ static void event_loop(void) if (poll_array[POLL_SCN].revents) isns_scn_handle(0); + if (poll_array[POLL_ISER_LISTEN].revents) + iser_accept(poll_array[POLL_ISER_LISTEN].fd); + for (i = 0; i < INCOMING_MAX; i++) { struct connection *conn = incoming[i]; struct pollfd *pollfd = &poll_array[POLL_INCOMING + i]; diff --git a/iscsi-scst/usr/iscsid.c b/iscsi-scst/usr/iscsid.c index 615cec4c1..703548006 100644 --- a/iscsi-scst/usr/iscsid.c +++ b/iscsi-scst/usr/iscsid.c @@ -42,6 +42,10 @@ static struct iscsi_key login_keys[] = { {"InitiatorAlias",}, {"SessionType",}, {"TargetName",}, + {"InitiatorRecvDataSegmentLength",}, + {"MaxAHSLength",}, + {"TaggedBufferForSolicitedDataOnly",}, + {"iSERHelloRequired",}, {NULL,}, }; @@ -370,6 +374,26 @@ static void text_scan_login(struct connection *conn) } } + if (conn->is_iser) { + switch (idx) { + case key_rdma_extensions: + if (val != 1) { + login_rsp_ini_err(conn, ISCSI_STATUS_INIT_ERR); + goto out; + } + break; + case key_initial_r2t: + val = 1; + break; + case key_immediate_data: + val = 0; + break; + } + } else if (idx == key_rdma_extensions && val != 0) { + login_rsp_ini_err(conn, ISCSI_STATUS_INIT_ERR); + goto out; + } + params_check_val(session_keys, idx, &val); params_set_val(session_keys, conn->session_params, idx, &val); @@ -503,6 +527,11 @@ static void login_start(struct connection *conn) if (session_type) { if (!strcmp(session_type, "Discovery")) { + int ret = conn->is_discovery(conn->fd); + if (ret) { + login_rsp_tgt_err(conn, ISCSI_STATUS_MISSING_FIELDS); + return; + } conn->session_type = SESSION_DISCOVERY; } else if (strcmp(session_type, "Normal")) { login_rsp_ini_err(conn, ISCSI_STATUS_INV_SESSION_TYPE); diff --git a/iscsi-scst/usr/iscsid.h b/iscsi-scst/usr/iscsid.h index 2a3b4490e..eb0cbce9d 100644 --- a/iscsi-scst/usr/iscsid.h +++ b/iscsi-scst/usr/iscsid.h @@ -28,8 +28,10 @@ #include "types.h" #ifdef INSIDE_KERNEL_TREE #include +#include #else #include "iscsi_scst.h" +#include "isert_scst.h" #endif #include "iscsi_hdr.h" #include "param.h" @@ -128,7 +130,11 @@ struct connection { struct __qelem clist; + bool is_iser; + int (*transmit)(int fd, bool start); + int (*getsockname)(int fd, struct sockaddr *name, socklen_t *namelen); + int (*is_discovery)(int fd); }; #define IOSTATE_FREE 0 @@ -224,6 +230,7 @@ extern int conn_blocked; enum { POLL_LISTEN, POLL_IPC = POLL_LISTEN + LISTEN_MAX, + POLL_ISER_LISTEN, POLL_NL, POLL_ISNS, POLL_SCN_LISTEN, diff --git a/iscsi-scst/usr/param.c b/iscsi-scst/usr/param.c index 9c524cde7..420e1308f 100644 --- a/iscsi-scst/usr/param.c +++ b/iscsi-scst/usr/param.c @@ -383,5 +383,13 @@ struct iscsi_key session_keys[] = { {"IFMarker", 0, 0, 0, 0, 0, &and_ops}, {"OFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops}, {"IFMarkInt", 2048, 2048, 1, 65535, 0, &marker_ops}, + {"RDMAExtensions", 0, 0, 0, 0, 1, &and_ops}, + {"TargetRecvDataSegmentLength", 8192, -1, 512, -1, 0, &minimum_ops}, + {"InitiatorRecvDataSegmentLength", 8192, -1, 512, -1, 0, &minimum_ops}, + {"MaxAHSLength", 256, 0, 0, -1, 0, &minimum_ops}, + {"TaggedBufferForSolicitedDataOnly", 0, 0, 0, 0, 0, &and_ops}, + {"iSERHelloRequired", 0, 0, 0, 0, 0, &and_ops}, + {"MaxOutstandingUnexpectedPDUs", 0, 0, 0, -1, 0, &minimum_ops}, {NULL,}, }; + diff --git a/iscsi-scst/usr/target.c b/iscsi-scst/usr/target.c index 2d475edb1..ecc00ec6d 100644 --- a/iscsi-scst/usr/target.c +++ b/iscsi-scst/usr/target.c @@ -239,10 +239,11 @@ void target_list_build(struct connection *conn, char *target_name) char portal[NI_MAXHOST]; int family, i; - if (getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) { + if (conn->getsockname(conn->fd, (struct sockaddr *) &ss1, &slen)) { log_error("getsockname failed: %m"); return; } + family = ss1.ss_family; list_for_each_entry(target, &targets_list, tlist) {