Author: trasz Date: Fri Feb 6 21:03:25 2015 New Revision: 278331 URL: https://svnweb.freebsd.org/changeset/base/278331
Log: Make it possible to set (via ctl.conf(5)) and query (via ctladm islist -v) target iSCSI offload. Add mechanism to query maximum receive data segment size supported by chosen hardware offload module, and use it in ctld(8) to determine the value to advertise to the other side. MFC after: 1 month Sponsored by: The FreeBSD Foundation Modified: head/sys/cam/ctl/ctl_frontend_iscsi.c head/sys/cam/ctl/ctl_ioctl.h head/usr.sbin/ctladm/ctladm.c head/usr.sbin/ctld/ctl.conf.5 head/usr.sbin/ctld/ctld.c head/usr.sbin/ctld/ctld.h head/usr.sbin/ctld/kernel.c head/usr.sbin/ctld/login.c head/usr.sbin/ctld/parse.y head/usr.sbin/ctld/token.l Modified: head/sys/cam/ctl/ctl_frontend_iscsi.c ============================================================================== --- head/sys/cam/ctl/ctl_frontend_iscsi.c Fri Feb 6 20:52:01 2015 (r278330) +++ head/sys/cam/ctl/ctl_frontend_iscsi.c Fri Feb 6 21:03:25 2015 (r278331) @@ -1222,7 +1222,7 @@ cfiscsi_session_unregister_initiator(str } static struct cfiscsi_session * -cfiscsi_session_new(struct cfiscsi_softc *softc) +cfiscsi_session_new(struct cfiscsi_softc *softc, const char *offload) { struct cfiscsi_session *cs; int error; @@ -1242,7 +1242,11 @@ cfiscsi_session_new(struct cfiscsi_softc cv_init(&cs->cs_login_cv, "cfiscsi_login"); #endif - cs->cs_conn = icl_new_conn(NULL, "cfiscsi", &cs->cs_lock); + cs->cs_conn = icl_new_conn(offload, "cfiscsi", &cs->cs_lock); + if (cs->cs_conn == NULL) { + free(cs, M_CFISCSI); + return (NULL); + } cs->cs_conn->ic_receive = cfiscsi_receive_callback; cs->cs_conn->ic_error = cfiscsi_error_callback; cs->cs_conn->ic_prv0 = cs; @@ -1325,7 +1329,7 @@ cfiscsi_accept(struct socket *so, struct { struct cfiscsi_session *cs; - cs = cfiscsi_session_new(&cfiscsi_softc); + cs = cfiscsi_session_new(&cfiscsi_softc, NULL); if (cs == NULL) { CFISCSI_WARN("failed to create session"); return; @@ -1469,7 +1473,7 @@ cfiscsi_ioctl_handoff(struct ctl_iscsi * mtx_unlock(&cfiscsi_softc.lock); } else { #endif - cs = cfiscsi_session_new(softc); + cs = cfiscsi_session_new(softc, cihp->offload); if (cs == NULL) { ci->status = CTL_ISCSI_ERROR; snprintf(ci->error_str, sizeof(ci->error_str), @@ -1620,6 +1624,7 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci) "<max_data_segment_length>%zd</max_data_segment_length>" "<immediate_data>%d</immediate_data>" "<iser>%d</iser>" + "<offload>%s</offload>" "</connection>\n", cs->cs_id, cs->cs_initiator_name, cs->cs_initiator_addr, cs->cs_initiator_alias, @@ -1629,7 +1634,8 @@ cfiscsi_ioctl_list(struct ctl_iscsi *ci) cs->cs_conn->ic_data_crc32c ? "CRC32C" : "None", cs->cs_max_data_segment_length, cs->cs_immediate_data, - cs->cs_conn->ic_iser); + cs->cs_conn->ic_iser, + cs->cs_conn->ic_offload); if (error != 0) break; } @@ -1749,6 +1755,26 @@ cfiscsi_ioctl_logout(struct ctl_iscsi *c ci->status = CTL_ISCSI_OK; } +static void +cfiscsi_ioctl_limits(struct ctl_iscsi *ci) +{ + struct ctl_iscsi_limits_params *cilp; + int error; + + cilp = (struct ctl_iscsi_limits_params *)&(ci->data); + + error = icl_limits(cilp->offload, &cilp->data_segment_limit); + if (error != 0) { + ci->status = CTL_ISCSI_ERROR; + snprintf(ci->error_str, sizeof(ci->error_str), + "%s: icl_limits failed with error %d", + __func__, error); + return; + } + + ci->status = CTL_ISCSI_OK; +} + #ifdef ICL_KERNEL_PROXY static void cfiscsi_ioctl_listen(struct ctl_iscsi *ci) @@ -2176,6 +2202,9 @@ cfiscsi_ioctl(struct cdev *dev, case CTL_ISCSI_LOGOUT: cfiscsi_ioctl_logout(ci); break; + case CTL_ISCSI_LIMITS: + cfiscsi_ioctl_limits(ci); + break; #ifdef ICL_KERNEL_PROXY case CTL_ISCSI_LISTEN: cfiscsi_ioctl_listen(ci); Modified: head/sys/cam/ctl/ctl_ioctl.h ============================================================================== --- head/sys/cam/ctl/ctl_ioctl.h Fri Feb 6 20:52:01 2015 (r278330) +++ head/sys/cam/ctl/ctl_ioctl.h Fri Feb 6 21:03:25 2015 (r278331) @@ -657,6 +657,7 @@ typedef enum { CTL_ISCSI_LIST, CTL_ISCSI_LOGOUT, CTL_ISCSI_TERMINATE, + CTL_ISCSI_LIMITS, #if defined(ICL_KERNEL_PROXY) || 1 /* * We actually need those in all cases, but leave the ICL_KERNEL_PROXY, @@ -677,6 +678,7 @@ typedef enum { #define CTL_ISCSI_NAME_LEN 224 /* 223 bytes, by RFC 3720, + '\0' */ #define CTL_ISCSI_ADDR_LEN 47 /* INET6_ADDRSTRLEN + '\0' */ #define CTL_ISCSI_ALIAS_LEN 128 /* Arbitrary. */ +#define CTL_ISCSI_OFFLOAD_LEN 8 /* Arbitrary. */ struct ctl_iscsi_handoff_params { char initiator_name[CTL_ISCSI_NAME_LEN]; @@ -698,11 +700,12 @@ struct ctl_iscsi_handoff_params { uint32_t max_burst_length; uint32_t first_burst_length; uint32_t immediate_data; + char offload[CTL_ISCSI_OFFLOAD_LEN]; #ifdef ICL_KERNEL_PROXY int connection_id; - int spare[3]; + int spare[1]; #else - int spare[4]; + int spare[2]; #endif }; @@ -733,6 +736,14 @@ struct ctl_iscsi_terminate_params { int spare[4]; }; +struct ctl_iscsi_limits_params { + char offload[CTL_ISCSI_OFFLOAD_LEN]; + /* passed to kernel */ + size_t data_segment_limit; + /* passed to userland */ + int spare[4]; +}; + #ifdef ICL_KERNEL_PROXY struct ctl_iscsi_listen_params { int iser; @@ -780,6 +791,7 @@ union ctl_iscsi_data { struct ctl_iscsi_list_params list; struct ctl_iscsi_logout_params logout; struct ctl_iscsi_terminate_params terminate; + struct ctl_iscsi_limits_params limits; #ifdef ICL_KERNEL_PROXY struct ctl_iscsi_listen_params listen; struct ctl_iscsi_accept_params accept; Modified: head/usr.sbin/ctladm/ctladm.c ============================================================================== --- head/usr.sbin/ctladm/ctladm.c Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctladm/ctladm.c Fri Feb 6 21:03:25 2015 (r278331) @@ -3439,6 +3439,7 @@ struct cctl_islist_conn { char *header_digest; char *data_digest; char *max_data_segment_length;; + char *offload;; int immediate_data; int iser; STAILQ_ENTRY(cctl_islist_conn) links; @@ -3552,6 +3553,9 @@ cctl_islist_end_element(void *user_data, } else if (strcmp(name, "max_data_segment_length") == 0) { cur_conn->max_data_segment_length = str; str = NULL; + } else if (strcmp(name, "offload") == 0) { + cur_conn->offload = str; + str = NULL; } else if (strcmp(name, "immediate_data") == 0) { cur_conn->immediate_data = atoi(str); } else if (strcmp(name, "iser") == 0) { @@ -3672,6 +3676,7 @@ retry: printf("DataSegmentLen: %s\n", conn->max_data_segment_length); printf("ImmediateData: %s\n", conn->immediate_data ? "Yes" : "No"); printf("iSER (RDMA): %s\n", conn->iser ? "Yes" : "No"); + printf("Offload driver: %s\n", conn->offload); printf("\n"); } } else { Modified: head/usr.sbin/ctld/ctl.conf.5 ============================================================================== --- head/usr.sbin/ctld/ctl.conf.5 Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/ctl.conf.5 Fri Feb 6 21:03:25 2015 (r278331) @@ -310,6 +310,8 @@ This clause is mutually exclusive with .Sy auth-group ; one cannot use both in a single target. +.It Ic offload Ar driver +Define iSCSI hardware offload driver to use for this target. .It Ic portal-group Ar name Op Ar agname Assign a previously defined portal group to the target. The default portal group is Modified: head/usr.sbin/ctld/ctld.c ============================================================================== --- head/usr.sbin/ctld/ctld.c Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/ctld.c Fri Feb 6 21:03:25 2015 (r278331) @@ -1272,6 +1272,22 @@ target_set_redirection(struct target *ta return (0); } +int +target_set_offload(struct target *target, const char *offload) +{ + + if (target->t_offload != NULL) { + log_warnx("cannot set offload to \"%s\" for " + "target \"%s\"; already defined", + offload, target->t_name); + return (1); + } + + target->t_offload = checked_strdup(offload); + + return (0); +} + struct lun * lun_new(struct conf *conf, const char *name) { @@ -1514,6 +1530,8 @@ conf_print(struct conf *conf) fprintf(stderr, "target %s {\n", targ->t_name); if (targ->t_alias != NULL) fprintf(stderr, "\t alias %s\n", targ->t_alias); + if (targ->t_offload != NULL) + fprintf(stderr, "\t offload %s\n", targ->t_offload); fprintf(stderr, "}\n"); } } Modified: head/usr.sbin/ctld/ctld.h ============================================================================== --- head/usr.sbin/ctld/ctld.h Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/ctld.h Fri Feb 6 21:03:25 2015 (r278331) @@ -169,6 +169,7 @@ struct target { TAILQ_HEAD(, port) t_ports; char *t_name; char *t_alias; + char *t_offload; char *t_redirection; }; @@ -223,6 +224,7 @@ struct connection { struct sockaddr_storage conn_initiator_sa; uint32_t conn_cmdsn; uint32_t conn_statsn; + size_t conn_data_segment_limit; size_t conn_max_data_segment_length; size_t conn_max_burst_length; int conn_immediate_data; @@ -344,6 +346,8 @@ struct target *target_find(struct conf const char *name); int target_set_redirection(struct target *target, const char *addr); +int target_set_offload(struct target *target, + const char *offload); struct lun *lun_new(struct conf *conf, const char *name); void lun_delete(struct lun *lun); @@ -370,6 +374,8 @@ int kernel_lun_add(struct lun *lun); int kernel_lun_resize(struct lun *lun); int kernel_lun_remove(struct lun *lun); void kernel_handoff(struct connection *conn); +void kernel_limits(const char *offload, + size_t *max_data_segment_length); int kernel_port_add(struct port *port); int kernel_port_update(struct port *port); int kernel_port_remove(struct port *port); Modified: head/usr.sbin/ctld/kernel.c ============================================================================== --- head/usr.sbin/ctld/kernel.c Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/kernel.c Fri Feb 6 21:03:25 2015 (r278331) @@ -799,6 +799,10 @@ kernel_handoff(struct connection *conn) sizeof(req.data.handoff.initiator_isid)); strlcpy(req.data.handoff.target_name, conn->conn_target->t_name, sizeof(req.data.handoff.target_name)); + if (conn->conn_target->t_offload != NULL) { + strlcpy(req.data.handoff.offload, + conn->conn_target->t_offload, sizeof(req.data.handoff.offload)); + } #ifdef ICL_KERNEL_PROXY if (proxy_mode) req.data.handoff.connection_id = conn->conn_socket; @@ -831,6 +835,39 @@ kernel_handoff(struct connection *conn) } } +void +kernel_limits(const char *offload, size_t *max_data_segment_length) +{ + struct ctl_iscsi req; + + bzero(&req, sizeof(req)); + + req.type = CTL_ISCSI_LIMITS; + if (offload != NULL) { + strlcpy(req.data.limits.offload, offload, + sizeof(req.data.limits.offload)); + } + + if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { + log_err(1, "error issuing CTL_ISCSI ioctl; " + "dropping connection"); + } + + if (req.status != CTL_ISCSI_OK) { + log_errx(1, "error returned from CTL iSCSI limits request: " + "%s; dropping connection", req.error_str); + } + + *max_data_segment_length = req.data.limits.data_segment_limit; + if (offload != NULL) { + log_debugx("MaxRecvDataSegment kernel limit for offload " + "\"%s\" is %zd", offload, *max_data_segment_length); + } else { + log_debugx("MaxRecvDataSegment kernel limit is %zd", + *max_data_segment_length); + } +} + int kernel_port_add(struct port *port) { Modified: head/usr.sbin/ctld/login.c ============================================================================== --- head/usr.sbin/ctld/login.c Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/login.c Fri Feb 6 21:03:25 2015 (r278331) @@ -453,7 +453,8 @@ static void login_negotiate_key(struct pdu *request, const char *name, const char *value, bool skipped_security, struct keys *response_keys) { - int which, tmp; + int which; + size_t tmp; struct connection *conn; conn = request->pdu_connection; @@ -552,13 +553,13 @@ login_negotiate_key(struct pdu *request, log_errx(1, "received invalid " "MaxRecvDataSegmentLength"); } - if (tmp > MAX_DATA_SEGMENT_LENGTH) { + if (tmp > conn->conn_data_segment_limit) { log_debugx("capping MaxRecvDataSegmentLength " - "from %d to %d", tmp, MAX_DATA_SEGMENT_LENGTH); - tmp = MAX_DATA_SEGMENT_LENGTH; + "from %zd to %zd", tmp, conn->conn_data_segment_limit); + tmp = conn->conn_data_segment_limit; } conn->conn_max_data_segment_length = tmp; - keys_add_int(response_keys, name, MAX_DATA_SEGMENT_LENGTH); + keys_add_int(response_keys, name, tmp); } else if (strcmp(name, "MaxBurstLength") == 0) { tmp = strtoul(value, NULL, 10); if (tmp <= 0) { @@ -566,7 +567,7 @@ login_negotiate_key(struct pdu *request, log_errx(1, "received invalid MaxBurstLength"); } if (tmp > MAX_BURST_LENGTH) { - log_debugx("capping MaxBurstLength from %d to %d", + log_debugx("capping MaxBurstLength from %zd to %d", tmp, MAX_BURST_LENGTH); tmp = MAX_BURST_LENGTH; } @@ -579,10 +580,10 @@ login_negotiate_key(struct pdu *request, log_errx(1, "received invalid " "FirstBurstLength"); } - if (tmp > MAX_DATA_SEGMENT_LENGTH) { - log_debugx("capping FirstBurstLength from %d to %d", - tmp, MAX_DATA_SEGMENT_LENGTH); - tmp = MAX_DATA_SEGMENT_LENGTH; + if (tmp > conn->conn_data_segment_limit) { + log_debugx("capping FirstBurstLength from %zd to %zd", + tmp, conn->conn_data_segment_limit); + tmp = conn->conn_data_segment_limit; } /* * We don't pass the value to the kernel; it only enforces @@ -680,6 +681,18 @@ login_negotiate(struct connection *conn, int i; bool redirected, skipped_security; + if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) { + /* + * Query the kernel for MaxDataSegmentLength it can handle. + * In case of offload, it depends on hardware capabilities. + */ + assert(conn->conn_target != NULL); + kernel_limits(conn->conn_target->t_offload, + &conn->conn_data_segment_limit); + } else { + conn->conn_data_segment_limit = MAX_DATA_SEGMENT_LENGTH; + } + if (request == NULL) { log_debugx("beginning operational parameter negotiation; " "waiting for Login PDU"); Modified: head/usr.sbin/ctld/parse.y ============================================================================== --- head/usr.sbin/ctld/parse.y Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/parse.y Fri Feb 6 21:03:25 2015 (r278331) @@ -60,7 +60,7 @@ extern void yyrestart(FILE *); %token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT -%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION +%token LISTEN LISTEN_ISER LUN MAXPROC OFFLOAD OPENING_BRACKET OPTION %token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR %token TARGET TIMEOUT @@ -463,6 +463,8 @@ target_entry: | target_initiator_portal | + target_offload + | target_portal_group | target_redirect @@ -652,6 +654,17 @@ target_initiator_portal: INITIATOR_PORTA } ; +target_offload: OFFLOAD STR + { + int error; + + error = target_set_offload(target, $2); + free($2); + if (error != 0) + return (1); + } + ; + target_portal_group: PORTAL_GROUP STR STR { struct portal_group *tpg; Modified: head/usr.sbin/ctld/token.l ============================================================================== --- head/usr.sbin/ctld/token.l Fri Feb 6 20:52:01 2015 (r278330) +++ head/usr.sbin/ctld/token.l Fri Feb 6 21:03:25 2015 (r278331) @@ -65,6 +65,7 @@ listen { return LISTEN; } listen-iser { return LISTEN_ISER; } lun { return LUN; } maxproc { return MAXPROC; } +offload { return OFFLOAD; } option { return OPTION; } path { return PATH; } pidfile { return PIDFILE; } _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"