summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGris Ge <fge@redhat.com>2018-01-19 21:30:52 +0800
committerGris Ge <fge@redhat.com>2018-01-22 18:26:06 +0800
commitf86c167662e7bf7b950b11b6a2f2939f3a38881c (patch)
treea7b6a25bd6141e9f4337f1c923d822ed3f779d77
parent3fa1142dc14f5b15ad2ded32a3c6f34e4457e2af (diff)
downloadopen-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/Makefile5
-rw-r--r--libopeniscsiusr/iface.c289
-rw-r--r--libopeniscsiusr/iface.h35
-rw-r--r--libopeniscsiusr/libopeniscsiusr/libopeniscsiusr.h1
-rw-r--r--libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_common.h2
-rw-r--r--libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_iface.h176
-rw-r--r--libopeniscsiusr/libopeniscsiusr/libopeniscsiusr_session.h20
-rw-r--r--libopeniscsiusr/session.c12
-rw-r--r--libopeniscsiusr/sysfs.c109
-rw-r--r--libopeniscsiusr/sysfs.h6
-rw-r--r--libopeniscsiusr/tests/test_session.c17
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(&regex,
+ "\\(.\\{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(&regex, 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(&regex);
+ 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);
}