From 09b34121c443998ffe4df38084b19696bd3ef902 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Fri, 27 Aug 2021 13:09:11 -0700 Subject: Handle qedi correctly in NPAR mode Use the correct driver, and handle the NPAR 4-MAC-ADDr offset of qedi, unlike other Offload cards. Found-by: David Bond --- utils/iscsi_offload | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/utils/iscsi_offload b/utils/iscsi_offload index 833d26f..1869fe1 100755 --- a/utils/iscsi_offload +++ b/utils/iscsi_offload @@ -85,10 +85,11 @@ iscsi_macaddress_from_pcifn() local h local host local ifmac + local olemacoffset=$3 ifmac=$(ip addr show dev $if | sed -n 's/ *link\/ether \(.*\) brd.*/\1/p') m5=$(( 0x${ifmac##*:} )) - m5=$(( $m5 + 1 )) + m5=$(( $m5 + $olemacoffset )) ifmac=$(printf "%s:%02x" ${ifmac%:*} $m5) for host in /sys/class/iscsi_host/host* ; do if [ -L "$host" ] ; then @@ -190,10 +191,7 @@ case "$driver" in qla*) mod=qla4xxx ;; - qede) - mod=qede - ;; - qedi) + qed*) mod=qedi ;; esac @@ -221,11 +219,11 @@ if [ "$mod" = "bnx2i" ] ; then elif [ "$mod" = "cxgb3i" ] ; then mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME) elif [ "$mod" = "be2iscsi" ] ; then - mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) + mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME 1) elif [ "$mod" = "qla4xxx" ] ; then - mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) + mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME 1) elif [ "$mod" = "qede" -o "$mod" = "qedi" ] ; then - mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) + mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME 4) fi if [ -z "$mac" ] ; then -- cgit v1.2.1 From d5df0d6149ff118351de25bae0fbf6f23df953d4 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Fri, 27 Aug 2021 13:20:23 -0700 Subject: Change iscsi IP type from defines to enum. This lets the compiler help us find errors, if any. Change the declaration and usage to match. Simplify the function that decides, while we are at it. Should be no functional change. --- include/iscsi_if.h | 7 +++++-- usr/iface.c | 35 ++++++++++++++++++++++------------- usr/iface.h | 2 +- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/iscsi_if.h b/include/iscsi_if.h index 5a1c614..22b7c09 100644 --- a/include/iscsi_if.h +++ b/include/iscsi_if.h @@ -393,8 +393,11 @@ struct iscsi_path { #define ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE 0x01 #define ISCSI_IPV6_ROUTER_AUTOCFG_DISABLE 0x02 -#define ISCSI_IFACE_TYPE_IPV4 0x01 -#define ISCSI_IFACE_TYPE_IPV6 0x02 +/* Interface IP Type */ +enum iscsi_iface_type { + ISCSI_IFACE_TYPE_IPV4 = 1, + ISCSI_IFACE_TYPE_IPV6, +}; #define ISCSI_MAX_VLAN_ID 4095 #define ISCSI_MAX_VLAN_PRIORITY 7 diff --git a/usr/iface.c b/usr/iface.c index 21d52b3..30f4ae0 100644 --- a/usr/iface.c +++ b/usr/iface.c @@ -445,25 +445,34 @@ int iface_get_by_net_binding(struct iface_rec *pattern, return ISCSI_ERR_NO_OBJS_FOUND; } -int iface_get_iptype(struct iface_rec *iface) +/* + * detect IPv4 vs IPv4 IP address + */ +enum iscsi_iface_type iface_get_iptype(struct iface_rec *iface) { + enum iscsi_iface_type res = ISCSI_IFACE_TYPE_IPV4; + /* address might not be set if user config with another tool */ if (!strlen(iface->ipaddress) || !strcmp(UNKNOWN_VALUE, iface->ipaddress)) { - /* try to figure out by name */ - if (strstr(iface->name, "ipv4")) - return ISCSI_IFACE_TYPE_IPV4; - else if (strstr(iface->name, "ipv6")) - return ISCSI_IFACE_TYPE_IPV6; - else /* assume ipv4 by default */ - return ISCSI_IFACE_TYPE_IPV4; + /* unknown or empty IP address: try to figure out by name */ + if (strstr(iface->name, "ipv6")) + res = ISCSI_IFACE_TYPE_IPV6; } else { + /* figure out what type of IP address string we have */ if (strcmp(iface->bootproto, "dhcp") && - !strstr(iface->ipaddress, ".")) - return ISCSI_IFACE_TYPE_IPV6; - else - return ISCSI_IFACE_TYPE_IPV4; + !strchr(iface->ipaddress, '.')) { + /* bootproto is NOT "dhcp", IP addr does NOT have a dot in it */ + res = ISCSI_IFACE_TYPE_IPV6; + } } + + log_debug(8, "iface: ipaddr=\"%s\" name=\"%s\" bootproto=\"%s\" -> %s", + iface->ipaddress, iface->name, + iface->bootproto, + res == ISCSI_IFACE_TYPE_IPV4 ? "IPv4" : "IPv6"); + + return res; } static int iface_setup_binding_from_kern_iface(void *data, @@ -1211,7 +1220,7 @@ static void iface_get_common_param_count(struct iface_rec *iface, int *count) static int __iface_get_param_count(void *data, struct iface_rec *iface) { struct iface_param_count *iface_params = data; - int iptype = ISCSI_IFACE_TYPE_IPV4; + enum iscsi_iface_type iptype; int count = 0; if (strcmp(iface_params->primary->hwaddress, iface->hwaddress)) diff --git a/usr/iface.h b/usr/iface.h index 6c06f7f..095772e 100644 --- a/usr/iface.h +++ b/usr/iface.h @@ -59,7 +59,7 @@ extern int iface_get_param_count(struct iface_rec *iface_primary, int iface_all); extern int iface_build_net_config(struct iface_rec *iface_primary, int iface_all, struct iovec *iovs); -extern int iface_get_iptype(struct iface_rec *iface); +extern enum iscsi_iface_type iface_get_iptype(struct iface_rec *iface); #define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]" #define iface_str(_iface) \ -- cgit v1.2.1 From 7260afb05f6f946f41fab52a8d3afad456cc5e75 Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Wed, 1 Sep 2021 11:48:19 -0700 Subject: Update iface.example for ipv6 Make it clear that ipv6 interface files need to have the string "ipv6" in their names. --- etc/iface.example | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/etc/iface.example b/etc/iface.example index 4b7f22c..17894cb 100644 --- a/etc/iface.example +++ b/etc/iface.example @@ -91,6 +91,13 @@ # example # iface.vlan_state = enable +# +# The IPv6 attributes require the interface file +# be named with the string "ipv6" in it. Otherwise, +# parsing such a file will cause errors, since IPv4 +# is otherwise assumed. +# + # OPTIONAL: iface.ipv6_linklocal # Specify the IPV6 Link Local Address with the # link local prefix of FE80::0/64 @@ -155,7 +162,7 @@ # # IPV6 sample config file with neighbor discovery: # BEGIN RECORD 2.0-872 -# iface.iscsi_ifacename = qla4xxx-3-1 +# iface.iscsi_ifacename = qla4xxx-3-1-ipv6 # iface.ipaddress = # iface.hwaddress = 00:0e:1e:04:93:92 # iface.transport_name = qla4xxx @@ -182,7 +189,7 @@ # Sample ipv6 config file(manual configured IPs): # BEGIN RECORD 2.0-872 -# iface.iscsi_ifacename = iface-new-file +# iface.iscsi_ifacename = iface-new-file-ipv6 # iface.ipaddress = fec0:ce00:7014:0041:1111:2222:1e04:9392 # iface.hwaddress = 00:0e:1e:04:93:92 # iface.transport_name = qla4xxx -- cgit v1.2.1 From cb39fb559a4046284925eb3a7457ed00b1e7b6fe Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Wed, 1 Sep 2021 11:50:15 -0700 Subject: Update iscsiadm man page Clarify/clean up the discovery mode synopsis, and clean up the description of discovery mode. --- doc/iscsiadm.8 | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 index 5fc6928..eea86d7 100644 --- a/doc/iscsiadm.8 +++ b/doc/iscsiadm.8 @@ -35,13 +35,12 @@ iscsiadm \- open-iscsi administration utility .RB [ \-P .IR printlevel ] .RB [ \-I -.IB iface\ \-t\ type\ \-p\ ip:port -.RB [ \-l ] -] | [ +.IR iface ] +.RB [ \-t +.IR type ] .RB [ \-p .IR ip:port ] -.RB [ \-l | \-D ] -] +.RB [ \-l ] .PP .B iscsiadm .B \-m node @@ -473,6 +472,11 @@ Specify the \fIindex\fR of the entity to operate on. This option is only valid for chap and flashnode submodes of host mode. .SH DISCOVERY TYPES iSCSI defines 3 discovery types: SendTargets, SLP, and iSNS. +.PP +A special discovery type called +.I fw +(for firmware) is also supported, for discoverying firmware interfaces, +and populating the interface database in the process. .TP .B SendTargets @@ -494,6 +498,7 @@ optionally the port of the iSNS server to do discovery to. .TP .B fw +Firmware mode. Several NICs and systems contain a mini iSCSI initiator which can be used for boot. To get the values used for boot the fw option can be used. Doing fw discovery, does not store persistent records in the node or @@ -503,17 +508,9 @@ resource. Performing fw discovery will print the portals, like with other discovery methods. To see other settings like CHAP values and initiator settings, like you would in node mode, run \fIiscsiadm \-m fw\fR. -.IP -fw support in open-iscsi is experimental. The settings and iscsiadm -syntax and output format may change. .P -iscsiadm supports the -.B -iSNS (isns) -or -.B -SendTargets (st) -discovery type. An SLP implementation is under development. +Note that the SLP implementation is under development and currently +is not supported. .SH EXIT STATUS On success 0 is returned. On error one of the return codes below will be returned. -- cgit v1.2.1 From 76350316de38abcd42afd3276249d577a0a66bec Mon Sep 17 00:00:00 2001 From: Lee Duncan Date: Wed, 1 Sep 2021 12:21:18 -0700 Subject: Handle IPv6 interfaces correctly. For IPv6 interface files (in iscsi/ifaces), assume the interface uses IPv4 unless it has "ipv6" in the name. Also, when creating interface files, name them ending with "ipv6.N" or "ipv4.N", where "N" is the interface number (normally zero). This was being done in one place, and this commit makes sure all places that create interface files use this convention. Note that iscsiadm cannot determine if the interface file is IPv6 vs IPv4 from the contents because of the way it processes those files: it creates a template of "legal" values, then processes the file. But it needs to know IPv4 vs IPv6 when creating the template. --- libopeniscsiusr/idbm.c | 18 ++++++++++++------ libopeniscsiusr/iface.c | 29 +++++++++++++++++++++++++++-- usr/iface.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/libopeniscsiusr/idbm.c b/libopeniscsiusr/idbm.c index 0910c63..b2524ed 100644 --- a/libopeniscsiusr/idbm.c +++ b/libopeniscsiusr/idbm.c @@ -303,7 +303,7 @@ struct idbm_rec { enum modify_mode can_modify; }; -static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs); +static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs, const char *iface_name); int _idbm_lock(struct iscsi_context *ctx) { @@ -394,6 +394,10 @@ static int _idbm_iface_rec_link(struct iscsi_iface *iface, struct idbm_rec *recs, int num) { int init_num = num; + + if (strstr(iface->name, "ipv6")) + iface->is_ipv6 = true; + if (init_num == 0) _rec_str(IFACE_ISCSINAME, recs, iface, name, IDBM_SHOW, num, _CANNOT_MODIFY); @@ -587,7 +591,7 @@ void _idbm_node_print(struct iscsi_node *node, FILE *f, bool show_secret) if (recs == NULL) return; - _idbm_node_rec_link(node, recs); + _idbm_node_rec_link(node, recs, NULL); _idbm_recs_print(recs, f, show_secret ? IDBM_SHOW : IDBM_MASKED); _idbm_recs_free(recs); } @@ -977,7 +981,7 @@ static struct int_list_tbl chap_algs[] = { { "SHA3-256", ISCSI_AUTH_CHAP_ALG_SHA3_256 }, }; -static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs) +static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs, const char *iface_name) { int num = 0; @@ -990,6 +994,10 @@ static void _idbm_node_rec_link(struct iscsi_node *node, struct idbm_rec *recs) _rec_bool(NODE_LEADING_LOGIN, recs, node, leading_login, IDBM_SHOW, num, _CAN_MODIFY); + /* use the interface name passed in, if any */ + if (iface_name) + strncpy((*node).iface.name, iface_name, ISCSI_MAX_IFACE_LEN); + /* * Note: because we do not add the iface.iscsi_ifacename to * sysfs iscsiadm does some weird matching. We can change the iface @@ -1153,7 +1161,7 @@ int _idbm_node_get(struct iscsi_context *ctx, const char *target_name, recs = _idbm_recs_alloc(); _alloc_null_check(ctx, recs, rc, out); - _idbm_node_rec_link(*node, recs); + _idbm_node_rec_link(*node, recs, iface_name); _good(_idbm_recs_read(ctx, recs, conf_path), rc, out); @@ -1180,8 +1188,6 @@ int _idbm_node_get(struct iscsi_context *ctx, const char *target_name, (*node)->conn.port); } - - out: if (rc != LIBISCSI_OK) { iscsi_node_free(*node); diff --git a/libopeniscsiusr/iface.c b/libopeniscsiusr/iface.c index 4d573fb..63f9c61 100644 --- a/libopeniscsiusr/iface.c +++ b/libopeniscsiusr/iface.c @@ -86,6 +86,29 @@ _iscsi_getter_func_gen(iscsi_iface, port_state, const char *); _iscsi_getter_func_gen(iscsi_iface, port_speed, const char *); _iscsi_getter_func_gen(iscsi_iface, name, const char *); +/* + * ipv6 address strings will have at least two colons + * + * NOTE: does NOT validate the IP address + */ +static bool lib_ipaddr_is_ipv6(struct iscsi_context *ctx, char *ipaddr) +{ + char *first_colon, *second_colon; + bool res = false; + + if (ipaddr) { + first_colon = strchr(ipaddr, ':'); + if (first_colon) { + second_colon = strchr(first_colon+1, ':'); + if (second_colon && + (second_colon != first_colon)) + res = true; + } + } + _debug(ctx, "ipaddr=\"%s\" -> %u", ipaddr, res); + return res; +} + int _iscsi_iface_get_from_sysfs(struct iscsi_context *ctx, uint32_t host_id, uint32_t sid, char *iface_kern_id, struct iscsi_iface **iface) @@ -203,8 +226,10 @@ int _iscsi_iface_get_from_sysfs(struct iscsi_context *ctx, uint32_t host_id, if (bound_by_hwaddr) snprintf((*iface)->name, sizeof((*iface)->name)/sizeof(char), - "%s.%s", (*iface)->transport_name, - (*iface)->hwaddress); + "%s.%s.%s.%u", (*iface)->transport_name, + (*iface)->hwaddress, + lib_ipaddr_is_ipv6(ctx, (*iface)->ipaddress) ? "ipv6" : "ipv4", + (*iface)->iface_num); } if (strcmp((*iface)->name, "") == 0) { diff --git a/usr/iface.c b/usr/iface.c index 30f4ae0..9db73c3 100644 --- a/usr/iface.c +++ b/usr/iface.c @@ -995,6 +995,30 @@ void iface_link_ifaces(struct list_head *ifaces) iface_for_each_iface(ifaces, 1, &nr_found, iface_link); } +/* + * ipv6 address strings will have at least two colons + * + * NOTE: does NOT validate the IP address + */ +static bool ipaddr_is_ipv6(char *ipaddr) +{ + char *first_colon, *second_colon; + bool res = false; + + if (ipaddr) { + first_colon = strchr(ipaddr, ':'); + if (first_colon) { + second_colon = strchr(first_colon+1, ':'); + if (second_colon && + (second_colon != first_colon)) + res = true; + } + } + log_debug(8, "%s(%s) -> %u", + __FUNCTION__, ipaddr, res); + return res; +} + /** * iface_setup_from_boot_context - setup iface from boot context info * @iface: iface t setup @@ -1068,9 +1092,6 @@ int iface_setup_from_boot_context(struct iface_rec *iface, } strcpy(iface->transport_name, t->name); - memset(iface->name, 0, sizeof(iface->name)); - snprintf(iface->name, sizeof(iface->name), "%s.%s", - iface->transport_name, context->mac); strlcpy(iface->hwaddress, context->mac, sizeof(iface->hwaddress)); strlcpy(iface->ipaddress, context->ipaddr, @@ -1080,6 +1101,11 @@ int iface_setup_from_boot_context(struct iface_rec *iface, sizeof(iface->subnet_mask)); strlcpy(iface->gateway, context->gateway, sizeof(iface->gateway)); + snprintf(iface->name, sizeof(iface->name), "%s.%s.%s.%u", + iface->transport_name, context->mac, + ipaddr_is_ipv6(iface->ipaddress) ? "ipv6" : "ipv4", + iface->iface_num); + log_debug(1, "iface " iface_fmt "", iface_str(iface)); return 1; } -- cgit v1.2.1