diff options
author | Gris Ge <fge@redhat.com> | 2018-01-19 21:30:52 +0800 |
---|---|---|
committer | Gris Ge <fge@redhat.com> | 2018-01-22 18:26:06 +0800 |
commit | f86c167662e7bf7b950b11b6a2f2939f3a38881c (patch) | |
tree | a7b6a25bd6141e9f4337f1c923d822ed3f779d77 | |
parent | 3fa1142dc14f5b15ad2ded32a3c6f34e4457e2af (diff) | |
download | open-iscsi-f86c167662e7bf7b950b11b6a2f2939f3a38881c.tar.gz |
libopeniscsiusr: Add basic iface support into iscsi session.
* New function `iscsi_session_iface_get()` to query in use iface of
specified iscsi session.
* Only basic information included required by command
'iscsiadm -m session -P 3'
* The iface name does not support old kernel yet. Will fix that in
full iface support patches.
Signed-off-by: Gris Ge <fge@redhat.com>
-rw-r--r-- | libopeniscsiusr/Makefile | 5 | ||||
-rw-r--r-- | libopeniscsiusr/iface.c | 289 | ||||
-rw-r--r-- | libopeniscsiusr/iface.h | 35 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h | 1 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h | 2 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h | 176 | ||||
-rw-r--r-- | libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h | 20 | ||||
-rw-r--r-- | libopeniscsiusr/session.c | 12 | ||||
-rw-r--r-- | libopeniscsiusr/sysfs.c | 109 | ||||
-rw-r--r-- | libopeniscsiusr/sysfs.h | 6 | ||||
-rw-r--r-- | libopeniscsiusr/tests/test_session.c | 17 |
11 files changed, 670 insertions, 2 deletions
diff --git a/libopeniscsiusr/Makefile b/libopeniscsiusr/Makefile index 143a177..8b9b523 100644 --- a/libopeniscsiusr/Makefile +++ b/libopeniscsiusr/Makefile @@ -34,11 +34,12 @@ LIBS_MAJOR = $(DEVLIB).$(LIBISCSI_USR_VERSION_MAJOR) PKGFILE = libopeniscsiusr.pc HEADERS = libopeniscsiusr/libopeniscsiusr.h \ libopeniscsiusr/libopeniscsiusr_common.h \ - libopeniscsiusr/libopeniscsiusr_session.h + libopeniscsiusr/libopeniscsiusr_session.h \ + libopeniscsiusr/libopeniscsiusr_iface.h TESTS = tests/test_context tests/test_session EXTRA_MAN_FILES = libopeniscsiusr.h.3 -OBJS = context.o misc.o session.o sysfs.o +OBJS = context.o misc.o session.o sysfs.o iface.o CFLAGS ?= -O2 -g CFLAGS += -Wall -Werror -Wextra -fvisibility=hidden -fPIC diff --git a/libopeniscsiusr/iface.c b/libopeniscsiusr/iface.c new file mode 100644 index 0000000..79898df --- /dev/null +++ b/libopeniscsiusr/iface.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Gris Ge <fge@redhat.com> + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* For NI_MAXHOST */ +#endif + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <dirent.h> +#include <string.h> +#include <net/if.h> +#include <netdb.h> +#include <assert.h> +#include <inttypes.h> + +#include "libopeniscsiusr/libopeniscsiusr.h" +#include "misc.h" +#include "sysfs.h" +#include "iface.h" + +#define ISCSI_MAX_IFACE_LEN 65 +#define ISCSI_TRANSPORT_NAME_MAXLEN 16 +#define ISCSI_MAX_STR_LEN 80 +#define ISCSI_HWADDRESS_BUF_SIZE 18 +#define TARGET_NAME_MAXLEN 255 +/* ^ TODO(Gris Ge): Above 5 constants are copy from usr/config.h, need to + * verify them in linux kernel code + */ + +#define DEFAULT_IFACENAME "default" +#define DEFAULT_NETDEV "default" +#define DEFAULT_IPADDRESS "default" +#define DEFAULT_HWADDRESS "default" + + +/* Just copy from `struct iface_rec` from usr/config.h */ +struct iscsi_iface { + /* iscsi iface record name */ + char name[ISCSI_MAX_IFACE_LEN]; + uint32_t iface_num; + /* network layer iface name (eth0) */ + char netdev[IFNAMSIZ]; + char ipaddress[NI_MAXHOST]; + char subnet_mask[NI_MAXHOST]; + char gateway[NI_MAXHOST]; + char bootproto[ISCSI_MAX_STR_LEN]; + char ipv6_linklocal[NI_MAXHOST]; + char ipv6_router[NI_MAXHOST]; + char ipv6_autocfg[NI_MAXHOST]; + char linklocal_autocfg[NI_MAXHOST]; + char router_autocfg[NI_MAXHOST]; + uint16_t vlan_id; + uint8_t vlan_priority; + char vlan_state[ISCSI_MAX_STR_LEN]; + char state[ISCSI_MAX_STR_LEN]; /* 0 = disable, + * 1 = enable */ + uint16_t mtu; + uint16_t port; + char delayed_ack[ISCSI_MAX_STR_LEN]; + char nagle[ISCSI_MAX_STR_LEN]; + char tcp_wsf_state[ISCSI_MAX_STR_LEN]; + uint8_t tcp_wsf; + uint8_t tcp_timer_scale; + char tcp_timestamp[ISCSI_MAX_STR_LEN]; + char dhcp_dns[ISCSI_MAX_STR_LEN]; + char dhcp_slp_da[ISCSI_MAX_STR_LEN]; + char tos_state[ISCSI_MAX_STR_LEN]; + uint8_t tos; + char gratuitous_arp[ISCSI_MAX_STR_LEN]; + char dhcp_alt_client_id_state[ISCSI_MAX_STR_LEN]; + char dhcp_alt_client_id[ISCSI_MAX_STR_LEN]; + char dhcp_req_vendor_id_state[ISCSI_MAX_STR_LEN]; + char dhcp_vendor_id_state[ISCSI_MAX_STR_LEN]; + char dhcp_vendor_id[ISCSI_MAX_STR_LEN]; + char dhcp_learn_iqn[ISCSI_MAX_STR_LEN]; + char fragmentation[ISCSI_MAX_STR_LEN]; + char incoming_forwarding[ISCSI_MAX_STR_LEN]; + uint8_t ttl; + char gratuitous_neighbor_adv[ISCSI_MAX_STR_LEN]; + char redirect[ISCSI_MAX_STR_LEN]; + char mld[ISCSI_MAX_STR_LEN]; + uint32_t flow_label; + uint32_t traffic_class; + uint8_t hop_limit; + uint32_t nd_reachable_tmo; + uint32_t nd_rexmit_time; + uint32_t nd_stale_tmo; + uint8_t dup_addr_detect_cnt; + uint32_t router_adv_link_mtu; + uint16_t def_task_mgmt_tmo; + char header_digest[ISCSI_MAX_STR_LEN]; + char data_digest[ISCSI_MAX_STR_LEN]; + char immediate_data[ISCSI_MAX_STR_LEN]; + char initial_r2t[ISCSI_MAX_STR_LEN]; + char data_seq_inorder[ISCSI_MAX_STR_LEN]; + char data_pdu_inorder[ISCSI_MAX_STR_LEN]; + uint8_t erl; + uint32_t max_recv_dlength; + uint32_t first_burst_len; + uint16_t max_out_r2t; + uint32_t max_burst_len; + char chap_auth[ISCSI_MAX_STR_LEN]; + char bidi_chap[ISCSI_MAX_STR_LEN]; + char strict_login_comp[ISCSI_MAX_STR_LEN]; + char discovery_auth[ISCSI_MAX_STR_LEN]; + char discovery_logout[ISCSI_MAX_STR_LEN]; + char port_state[ISCSI_MAX_STR_LEN]; + char port_speed[ISCSI_MAX_STR_LEN]; + /* + * TODO: we may have to make this bigger and interconnect + * specific for infiniband + */ + char hwaddress[ISCSI_HWADDRESS_BUF_SIZE]; + char transport_name[ISCSI_TRANSPORT_NAME_MAXLEN]; + /* + * This is only used for boot now, but the iser guys + * can use this for their virtualization idea. + */ + char alias[TARGET_NAME_MAXLEN + 1]; + char iname[TARGET_NAME_MAXLEN + 1]; +}; + +_iscsi_getter_func_gen(iscsi_iface, hwaddress, const char *); +_iscsi_getter_func_gen(iscsi_iface, transport_name, const char *); +_iscsi_getter_func_gen(iscsi_iface, ipaddress, const char *); +_iscsi_getter_func_gen(iscsi_iface, netdev, const char *); +_iscsi_getter_func_gen(iscsi_iface, iname, const char *); +_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 *); + +int _iscsi_iface_get(struct iscsi_context *ctx, uint32_t host_id, uint32_t sid, + const char *iface_kern_id, struct iscsi_iface **iface) +{ + int rc = LIBISCSI_OK; + char sysfs_se_dir_path[PATH_MAX]; + char sysfs_sh_dir_path[PATH_MAX]; + char sysfs_scsi_host_dir_path[PATH_MAX]; + char sysfs_iface_dir_path[PATH_MAX]; + char proc_name[ISCSI_TRANSPORT_NAME_MAXLEN]; + + assert(ctx != NULL); + assert(host_id != 0); + assert(sid != 0); + /* TODO(Gris Ge): Handle when sid == 0(ignored) */ + assert(iface != NULL); + + *iface = NULL; + + *iface = (struct iscsi_iface *) malloc(sizeof(struct iscsi_iface)); + _alloc_null_check(ctx, *iface, rc, out); + + snprintf(sysfs_se_dir_path, PATH_MAX, "%s/session%" PRIu32, + _ISCSI_SYS_SESSION_DIR, sid); + snprintf(sysfs_sh_dir_path, PATH_MAX, "%s/host%" PRIu32, + _ISCSI_SYS_HOST_DIR, host_id); + snprintf(sysfs_scsi_host_dir_path, PATH_MAX, "%s/host%" PRIu32, + _SCSI_SYS_HOST_DIR, host_id); + if (iface_kern_id != NULL) + snprintf(sysfs_iface_dir_path, PATH_MAX, "%s/%s", + _ISCSI_SYS_IFACE_DIR, iface_kern_id); + + _good(_sysfs_prop_get_str(ctx, sysfs_scsi_host_dir_path, "proc_name", + proc_name, sizeof(proc_name) / sizeof(char), + NULL /* raise error if failed */), + rc, out); + + if (strncmp(proc_name, "iscsi_", strlen("iscsi_")) == 0) + strncpy((*iface)->transport_name, proc_name + strlen("iscsi_"), + sizeof((*iface)->transport_name) / sizeof(char)); + else + strncpy((*iface)->transport_name, proc_name, + sizeof((*iface)->transport_name) / sizeof(char)); + + _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "hwaddress", + (*iface)->hwaddress, + sizeof((*iface)->hwaddress) / sizeof(char), + DEFAULT_HWADDRESS), + rc, out); + + if (iface_kern_id != NULL) + _good(_sysfs_prop_get_str(ctx, sysfs_iface_dir_path, + "ipaddress", + (*iface)->ipaddress, + sizeof((*iface)->ipaddress) / + sizeof(char), DEFAULT_IPADDRESS), + rc, out); + else + _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "ipaddress", + (*iface)->ipaddress, + sizeof((*iface)->ipaddress) / + sizeof(char), DEFAULT_IPADDRESS), + rc, out); + + _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "netdev", + (*iface)->netdev, + sizeof((*iface)->netdev) / sizeof(char), + DEFAULT_NETDEV), + rc, out); + + if (_sysfs_prop_get_str(NULL /* Ignore error */, sysfs_se_dir_path, + "initiatorname", + (*iface)->iname, + sizeof((*iface)->iname) / sizeof(char), + "") + != LIBISCSI_OK) { + _debug(ctx, "Failed to read initiatorname from %s folder", + sysfs_se_dir_path); + _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, + "initiatorname", (*iface)->iname, + sizeof((*iface)->iname) / + sizeof(char), ""), + rc, out); + } + + _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "port_state", + (*iface)->port_state, + sizeof((*iface)->port_state) / sizeof(char), + "unknown"), + rc, out); + + if (strcmp((*iface)->port_state, "Unknown!") == 0) + strncpy((*iface)->port_state, "unknown", + sizeof((*iface)->port_state) / sizeof(char)); + + _good(_sysfs_prop_get_str(ctx, sysfs_sh_dir_path, "port_speed", + (*iface)->port_speed, + sizeof((*iface)->port_speed) / sizeof(char), + "unknown"), + rc, out); + + if (strncmp((*iface)->port_speed, "Unknown", strlen("Unknown")) == 0) + strncpy((*iface)->port_speed, "unknown", + sizeof((*iface)->port_speed) / sizeof(char)); + + _good(_sysfs_prop_get_str(NULL /* Ignore error */, sysfs_se_dir_path, + "ifacename", + (*iface)->name, + sizeof((*iface)->name)/sizeof(char), + ""), + rc, out); + if (strcmp((*iface)->name, "") == 0) { + _debug(ctx, "Failed to query ifacename from %s folder", + sysfs_se_dir_path); + /* + * if the ifacename file is not there then we are + * using a older kernel and can try to find the + * binding by the net info which was used on these + * older kernels. + */ + + /*TODO(Gris Ge): need to parse /etc/iscsi/ifaces/<iface_name> + * files to find a match. I will add the code later when + * we expose more defiled information on iscsi_iface. + */ + strncpy((*iface)->name, DEFAULT_IFACENAME, + sizeof((*iface)->name) / sizeof(char)); + } + +out: + if (rc != LIBISCSI_OK) { + _iscsi_iface_free(*iface); + *iface = NULL; + } + return rc; +} + +void _iscsi_iface_free(struct iscsi_iface *iface) +{ + free(iface); +} diff --git a/libopeniscsiusr/iface.h b/libopeniscsiusr/iface.h new file mode 100644 index 0000000..85aa97c --- /dev/null +++ b/libopeniscsiusr/iface.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Gris Ge <fge@redhat.com> + */ +#ifndef __ISCSI_USR_IFACE_H__ +#define __ISCSI_USR_IFACE_H__ + +#include "libopeniscsiusr/libopeniscsiusr_common.h" +#include <stdint.h> + +/* + * BUG(Gris Ge): Should include 'iface_kern_id' parameter. + */ +__DLL_LOCAL int _iscsi_iface_get(struct iscsi_context *ctx, uint32_t host_id, + uint32_t sid, const char *iface_kern_id, + struct iscsi_iface **iface); + +__DLL_LOCAL void _iscsi_iface_free(struct iscsi_iface *iface); + + +#endif /* End of __ISCSI_USR_IFACE_H__ */ diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h index 45d42c1..bf8a845 100644 --- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h @@ -28,6 +28,7 @@ extern "C" { #include "libopeniscsiusr_common.h" #include "libopeniscsiusr_session.h" +#include "libopeniscsiusr_iface.h" /** * iscsi_log_priority_str() - Convert log priority to string. diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h index b001904..383ff19 100644 --- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h @@ -65,4 +65,6 @@ struct __DLL_EXPORT iscsi_context; struct __DLL_EXPORT iscsi_session; +struct __DLL_EXPORT iscsi_iface; + #endif /* End of _LIB_OPEN_ISCSI_USR_COMMON_H_ */ diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h new file mode 100644 index 0000000..ffba1f7 --- /dev/null +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Author: Gris Ge <fge@redhat.com> + */ + +#ifndef _LIB_OPEN_ISCSI_USR_IFACE_H_ +#define _LIB_OPEN_ISCSI_USR_IFACE_H_ + +#include "libopeniscsiusr_common.h" + +/** + * iscsi_iface_ipaddress_get() - Retrieve IP address of specified + * iSCSI interface + * + * Retrieve the IP address of specified iSCSI interface. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_ipaddress_get(struct iscsi_iface *iface); + +/** + * iscsi_iface_hwaddress_get() - Retrieve hardware address of specified + * iSCSI interface + * + * Retrieve the hardware address of specified iSCSI interface. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_hwaddress_get(struct iscsi_iface *iface); + +/** + * iscsi_iface_netdev_get() - Retrieve network device name of specified + * iSCSI interface + * + * Retrieve the network device name of specified iSCSI interface. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_netdev_get(struct iscsi_iface *iface); + +/** + * iscsi_iface_transport_name_get() - Retrieve transport name of specified + * iSCSI interface + * + * Retrieve the transport name of specified iSCSI interface. + * Examples: + * + * * "tcp" (Software iSCSI over TCP/IP) + * * "iser" (Software iSCSI over infinniband + * * "qla4xxx" (Qlogic QLA4XXX HBAs) + * * "bnx2i" (Broadcom bnx iSCSI HBAs); + * * "cxgb3i" (Chelsio cxgb S3 iSCSI HBAs); + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_transport_name_get + (struct iscsi_iface *iface); + +/** + * iscsi_iface_iname_get() - Retrieve initiator name of specified + * iSCSI interface + * + * Retrieve the initiator name of specified iSCSI interface. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_iname_get(struct iscsi_iface *iface); + +/** + * iscsi_iface_port_state_get() - Retrieve network port state of specified + * iSCSI interface + * + * Retrieve the network port state of specified iSCSI interface. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Possible values are : + * + * * "LINK_UP" + * + * * "LINK_DOWN" + * + * * "unknown" + * + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_port_state_get(struct iscsi_iface *iface); + +/** + * iscsi_iface_port_speed_get() - Retrieve network port speed of specified + * iSCSI interface + * + * Retrieve the network port speed of specified iSCSI interface. + * Returned string format is '[0-9]+ [MGT]bps', example: '10 Mbps' or '10 Gbps'. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. Set to "unknown" if unknown. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_port_speed_get(struct iscsi_iface *iface); + +/** + * iscsi_iface_port_speed_get() - Retrieve name of specified iSCSI interface + * + * Retrieve the name of specified iSCSI interface. + * + * @iface: + * Pointer of 'struct iscsi_iface'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * const char *. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT const char *iscsi_iface_name_get(struct iscsi_iface *iface); + +#endif /* End of _LIB_OPEN_ISCSI_USR_IFACE_H_ */ diff --git a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h index 4397258..30f8d7a 100644 --- a/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h +++ b/libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h @@ -328,4 +328,24 @@ __DLL_EXPORT const char *iscsi_session_address_get */ __DLL_EXPORT int32_t iscsi_session_port_get(struct iscsi_session *se); +/** + * iscsi_session_address_get() - Retrieve iSCSI interface information of + * specified session + * + * Retrieve the iSCSI interface information of specified iSCSI session. + * For the properties of 'struct iscsi_iface', please refer to the functions + * defined in 'libopeniscsiusr_iface.h' file. + * + * @se: + * Pointer of 'struct iscsi_session'. + * If this pointer is NULL, your program will be terminated by assert. + * + * Return: + * Pointer of 'struct iscsi_iface'. NULL if not supported. + * No need to free this memory, the resources will get freed by + * iscsi_session_free() or iscsi_sessions_free(). + */ +__DLL_EXPORT struct iscsi_iface *iscsi_session_iface_get + (struct iscsi_session *se); + #endif /* End of _LIB_OPEN_ISCSI_USR_SESSION_H_ */ diff --git a/libopeniscsiusr/session.c b/libopeniscsiusr/session.c index b7b39b2..ea3d9bc 100644 --- a/libopeniscsiusr/session.c +++ b/libopeniscsiusr/session.c @@ -35,6 +35,7 @@ #include "libopeniscsiusr/libopeniscsiusr.h" #include "misc.h" #include "sysfs.h" +#include "iface.h" #define _ISCSI_NAME_MAX_LEN 223 /* ^ RFC 3720: @@ -80,6 +81,7 @@ struct iscsi_session { char address[NI_MAXHOST + 1]; int32_t port; + struct iscsi_iface *iface; }; static uint32_t session_str_to_sid(const char *session_str); @@ -99,6 +101,7 @@ _iscsi_getter_func_gen(iscsi_session, abort_tmo, int32_t); _iscsi_getter_func_gen(iscsi_session, tpgt, int32_t); _iscsi_getter_func_gen(iscsi_session, address, const char *); _iscsi_getter_func_gen(iscsi_session, port, int32_t); +_iscsi_getter_func_gen(iscsi_session, iface, struct iscsi_iface *); /* * The session string is "session%u" used by /sys/class/iscsi_session/session%u. @@ -119,6 +122,7 @@ int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid, int rc = LIBISCSI_OK; char sysfs_se_dir_path[PATH_MAX]; char sysfs_con_dir_path[PATH_MAX]; + uint32_t host_id = 0; assert(ctx != NULL); assert(se != NULL); @@ -243,6 +247,12 @@ int iscsi_session_get(struct iscsi_context *ctx, uint32_t sid, ((*se)->port == -1)) (*se)->port = (*se)->persistent_port; + _good(_iscsi_host_id_of_session(ctx, sid, &host_id), rc, out); + + _good(_iscsi_iface_get(ctx, host_id, sid, NULL /*iface kernel id */, + &((*se)->iface)), + rc, out); + out: if (rc != LIBISCSI_OK) { iscsi_session_free(*se); @@ -323,6 +333,8 @@ out: void iscsi_session_free(struct iscsi_session *se) { + if (se != NULL) + _iscsi_iface_free(se->iface); free(se); } diff --git a/libopeniscsiusr/sysfs.c b/libopeniscsiusr/sysfs.c index c1aa576..70298f2 100644 --- a/libopeniscsiusr/sysfs.c +++ b/libopeniscsiusr/sysfs.c @@ -48,6 +48,9 @@ static int iscsi_sysfs_prop_get_ll(struct iscsi_context *ctx, const char *dir_path, const char *prop_name, long long int *val, long long int default_value); +static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path, + char *dev_path); + /* * dev_path should be char[PATH_MAX]. */ @@ -240,3 +243,109 @@ int _sysfs_prop_get_i32(struct iscsi_context *ctx, const char *dir_path, *val = tmp_val & INT32_MAX; return rc; } + +static int sysfs_get_dev_path(struct iscsi_context *ctx, const char *path, + char *dev_path) +{ + int rc = LIBISCSI_OK; + int errno_save = 0; + regex_t regex; + regmatch_t reg_match[2]; + int reg_rc = 0; + int need_free_reg = 0; + + assert(ctx != NULL); + assert(path != NULL); + assert(dev_path != NULL); + + memset(dev_path, 0, PATH_MAX); + + if (realpath(path, dev_path) == NULL) { + errno_save = errno; + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "realpath() failed on %s with error %d", path, + errno_save); + goto out; + } + + reg_rc = regcomp(®ex, + "\\(.\\{1,\\}/devices/.\\{1,\\}/host[0-9]\\{1,\\}\\)/" + "session[0-9]\\{1,\\}/iscsi_session/", + 0 /* no flag */); + /* ^ BUG(Gris Ge): This is based on GUESS, should check linux kernel + * code on this + */ + if (reg_rc != 0) { + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "regcomp() failed %d", reg_rc); + goto out; + } + need_free_reg = 1; + if (regexec(®ex, dev_path, 2 /* count of max matches */, + reg_match, 0 /* no flags */) != 0) { + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "regexec() not match for %s", dev_path); + goto out; + } + + *(dev_path + reg_match[1].rm_eo ) = '\0'; + + _debug(ctx, "Got dev path of '%s': '%s'", path, dev_path); + +out: + if (need_free_reg) + regfree(®ex); + if (rc != LIBISCSI_OK) + memset(dev_path, 0, PATH_MAX); + return rc; +} + +int _iscsi_host_id_of_session(struct iscsi_context *ctx, uint32_t sid, + uint32_t *host_id) +{ + int rc = LIBISCSI_OK; + char sys_se_dir_path[PATH_MAX]; + char sys_dev_path[PATH_MAX]; + char sys_scsi_host_dir_path[PATH_MAX]; + struct dirent **namelist = NULL; + int n = 0; + const char *host_id_str = NULL; + int i = 0; + + assert(ctx != NULL); + assert(sid != 0); + assert(host_id != NULL); + + snprintf(sys_se_dir_path, PATH_MAX, "%s/session%" PRIu32, + _ISCSI_SYS_SESSION_DIR, sid); + + *host_id = 0; + + _good(sysfs_get_dev_path(ctx, sys_se_dir_path, sys_dev_path), rc, out); + + snprintf(sys_scsi_host_dir_path, PATH_MAX, "%s/iscsi_host/", + sys_dev_path); + + n = scandir(sys_scsi_host_dir_path, &namelist, _scan_filter_skip_dot, + alphasort); + if (n != 1) { + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "Got unexpected(should be 1) file in folder %s", + sys_scsi_host_dir_path); + goto out; + } + host_id_str = namelist[0]->d_name; + + if (sscanf(host_id_str, "host%" SCNu32, host_id) != 1) { + rc = LIBISCSI_ERR_SYSFS_LOOKUP; + _error(ctx, "sscanf() failed on string %s", host_id_str); + goto out; + } + +out: + for (i = n - 1; i >= 0; --i) + free(namelist[i]); + free(namelist); + + return rc; +} diff --git a/libopeniscsiusr/sysfs.h b/libopeniscsiusr/sysfs.h index 835c0fe..3b501c2 100644 --- a/libopeniscsiusr/sysfs.h +++ b/libopeniscsiusr/sysfs.h @@ -25,6 +25,9 @@ #define _ISCSI_SYS_SESSION_DIR "/sys/class/iscsi_session" #define _ISCSI_SYS_CONNECTION_DIR "/sys/class/iscsi_connection" +#define _ISCSI_SYS_HOST_DIR "/sys/class/iscsi_host" +#define _ISCSI_SYS_IFACE_DIR "/sys/class/iscsi_iface" +#define _SCSI_SYS_HOST_DIR "/sys/class/scsi_host" /* * When default_value == NULL, treat no such file as LIB_BUG. @@ -48,4 +51,7 @@ __DLL_LOCAL int _sysfs_prop_get_i32(struct iscsi_context *ctx, const char *dir_path, const char *prop_name, int32_t *val, int32_t default_value); +__DLL_LOCAL int _iscsi_host_id_of_session(struct iscsi_context *ctx, + uint32_t sid, uint32_t *host_id); + #endif /* End of __ISCSI_USR_SYSFS_H__ */ diff --git a/libopeniscsiusr/tests/test_session.c b/libopeniscsiusr/tests/test_session.c index f7abc03..0f23f2e 100644 --- a/libopeniscsiusr/tests/test_session.c +++ b/libopeniscsiusr/tests/test_session.c @@ -58,6 +58,22 @@ } while(0) static void test_session(struct iscsi_session *se); +static void test_iface(struct iscsi_iface *iface); + +static void test_iface(struct iscsi_iface *iface) +{ + assert(iface != NULL); + printf("\t#### Interface info ####\n"); + _assert_print_prop_str_not_empty(iscsi_iface, iface, name); + _assert_print_prop_str_not_empty(iscsi_iface, iface, ipaddress); + _assert_print_prop_str_not_empty(iscsi_iface, iface, transport_name); + _assert_print_prop_str_not_empty(iscsi_iface, iface, iname); + _assert_print_prop_str_can_empty(iscsi_iface, iface, hwaddress); + _assert_print_prop_str_can_empty(iscsi_iface, iface, netdev); + _assert_print_prop_str_can_empty(iscsi_iface, iface, port_state); + _assert_print_prop_str_can_empty(iscsi_iface, iface, port_speed); + printf("\t########################\n"); +} static void test_session(struct iscsi_session *se) { @@ -99,6 +115,7 @@ int main() printf("\nGot %" PRIu32 " iSCSI sessions\n", se_count); for (i = 0; i < se_count; ++i) { test_session(ses[i]); + test_iface(iscsi_session_iface_get(ses[i])); } iscsi_sessions_free(ses, se_count); } |