[RFC-V2 PATCH 4/5] iscsi_transport: show network configuration in sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Vikas Chaudhary <vikas.chaudhary@xxxxxxxxxx>

To support multiple network addresses per adapter need to have a new way to
represent network interface (net iface) in sysfs.

Currently only one ipaddress and hwaddress is displayed

\# ls /sys/class/iscsi_host/host18
device  hwaddress  initiatorname  ipaddress  power  subsystem  uevent

In this patch the net iface is presented as a separate class device.
The one that can be added/removed dynamically or statically, based on how
the user configures the multiple net iface on the adapter.

The new sysfs directory would look like this
\# /sys/class/iscsi_iface/
|
|- ipv4-iface-<host_no>-<iface_no>/                             <-- for ipv4
                                |- ipaddress
                                |- subnet
                                |- gateway
                                |- bootproto
                                |- state
|- ipv6-iface-<host_no>-<iface_no>/                             <-- for ipv6
                                |- ipaddress
                                |- link_local_addr
                                |- router_addr
                                |- ipaddr_autocfg
                                |- linklocal_autocfg
                                |- state

We can also get above .iscsi_iface. class from:-
\# /sys/class/iscsi_host/host12/device/iscsi_iface/

With this change, iscsadm would need changes to create iface by getting
hw/ip related data from new sysfs path.
The old path still can be maintained to keep backward compatibility.

Signed-off-by: Vikas Chaudhary <vikas.chaudhary@xxxxxxxxxx>
Signed-off-by: Lalit Chandivade <lalit.chandivade@xxxxxxxxxx>
Reviewed-by: Harish Zunjarrao <harish.zunjarrao@xxxxxxxxxx>
---
 drivers/scsi/scsi_transport_iscsi.c |  215 ++++++++++++++++++++++++++++++++++-
 include/scsi/iscsi_if.h             |   17 +++
 include/scsi/scsi_transport_iscsi.h |   24 ++++
 3 files changed, 255 insertions(+), 1 deletions(-)

diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 38fcfc0..35ec15d 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/idr.h>
 #include <net/tcp.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -270,6 +271,190 @@ struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
 }
 EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
 
+
+/* Inerface to display network param to sysfs */
+
+static void iscsi_iface_release(struct device *dev)
+{
+	struct iscsi_iface *iface = iscsi_dev_to_iface(dev);
+	kfree(iface);
+}
+
+static struct class iscsi_iface_class = {
+	.name = "iscsi_iface",
+	.dev_release = iscsi_iface_release,
+};
+
+#define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store)	\
+struct device_attribute dev_attr_##_prefix##_##_name =		\
+	__ATTR(_name, _mode, _show, _store)
+
+/* iface attrs show */
+#define iscsi_iface_attr_show(type, name, param)			\
+static ssize_t								\
+show_##type##_##name(struct device *dev, struct device_attribute *attr,	\
+			char *buf)					\
+{									\
+	struct iscsi_iface *iface = iscsi_dev_to_iface(dev);		\
+	struct iscsi_transport *t = iface->transport;			\
+	return t->get_iface_param(iface, param, buf);			\
+}									\
+
+#define iscsi_iface_attr(type, name, param)				\
+	iscsi_iface_attr_show(type, name, param)			\
+static ISCSI_IFACE_ATTR(type, name, S_IRUGO, show_##type##_##name, NULL);
+
+/* generic read only ipvi4 attribute */
+iscsi_iface_attr(ipv4_iface, ipaddress, ISCSI_NET_PARAM_IPV4_ADDR);
+iscsi_iface_attr(ipv4_iface, gateway, ISCSI_NET_PARAM_IPV4_GW);
+iscsi_iface_attr(ipv4_iface, subnet, ISCSI_NET_PARAM_IPV4_SUBNET);
+iscsi_iface_attr(ipv4_iface, state, ISCSI_NET_PARAM_IFACE_STATE);
+iscsi_iface_attr(ipv4_iface, bootproto, ISCSI_NET_PARAM_IPV4_BOOTPROTO);
+
+/* generic read only ipv6 attribute */
+iscsi_iface_attr(ipv6_iface, ipaddress, ISCSI_NET_PARAM_IPV6_ADDR);
+iscsi_iface_attr(ipv6_iface, link_local_addr, ISCSI_NET_PARAM_IPV6_LINKLOCAL);
+iscsi_iface_attr(ipv6_iface, router_addr, ISCSI_NET_PARAM_IPV6_ROUTER);
+iscsi_iface_attr(ipv6_iface, ipaddr_autocfg,
+		 ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG);
+iscsi_iface_attr(ipv6_iface, linklocal_autocfg,
+		 ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG);
+iscsi_iface_attr(ipv6_iface, state, ISCSI_NET_PARAM_IFACE_STATE);
+
+/* IPv4 Attrs */
+#define ISCSI_IPV4_IFACE_ATTRS	5
+static struct attribute *iscsi_ipv4_iface_attrs[ISCSI_IPV4_IFACE_ATTRS + 1];
+
+#define SETUP_IPV4_IFACE_RD_ATTR(field, param_flag)			\
+do {									\
+	if (tt->ipv4_iface_param_mask & param_flag) {			\
+		iscsi_ipv4_iface_attrs[count] =				\
+		    &dev_attr_ipv4_iface_##field.attr;			\
+		count++;						\
+	}								\
+} while (0)
+
+static struct attribute_group iscsi_ipv4_iface_group = {
+	.attrs = iscsi_ipv4_iface_attrs,
+};
+
+/* IPv6 Attrs */
+#define ISCSI_IPV6_IFACE_ATTRS	6
+static struct attribute *iscsi_ipv6_iface_attrs[ISCSI_IPV6_IFACE_ATTRS + 1];
+
+#define SETUP_IPV6_IFACE_RD_ATTR(field, param_flag)			\
+do {									\
+	if (tt->ipv6_iface_param_mask & param_flag) {			\
+		iscsi_ipv6_iface_attrs[count] =				\
+		    &dev_attr_ipv6_iface_##field.attr;			\
+		count++;						\
+	}								\
+} while (0)
+
+static struct attribute_group iscsi_ipv6_iface_group = {
+	.attrs = iscsi_ipv6_iface_attrs,
+};
+
+static DEFINE_IDR(iscsi_iface_idr);
+static DEFINE_SPINLOCK(iscsi_iface_lock);
+
+struct iscsi_iface *
+iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport,
+		   uint32_t iface_type, uint32_t iface_num, int dd_size)
+{
+	struct iscsi_iface *iface;
+	int id;
+	int err;
+
+	iface = kzalloc(sizeof(*iface) + dd_size, GFP_KERNEL);
+	if (!iface)
+		return NULL;
+
+iface_idr_again:
+	if (!idr_pre_get(&iscsi_iface_idr, GFP_KERNEL))
+		goto free_iface;
+
+	spin_lock(&iscsi_iface_lock);
+	err = idr_get_new(&iscsi_iface_idr, iface, &id);
+	if (err == -EAGAIN) {
+		spin_unlock(&iscsi_iface_lock);
+		goto iface_idr_again;
+	}
+	spin_unlock(&iscsi_iface_lock);
+
+	if (err)
+		goto free_iface;
+
+	iface->id = id;
+	iface->transport = transport;
+	iface->iface_type = iface_type;
+	iface->iface_num = iface_num;
+	iface->dev.class = &iscsi_iface_class;
+	/* parent reference */
+	iface->dev.parent = get_device(&shost->shost_gendev);
+	if (iface_type == IFACE_TYPE_IPV4)
+		dev_set_name(&iface->dev, "ipv4-iface-%u-%u", shost->host_no,
+			     iface_num);
+	else if (iface_type == IFACE_TYPE_IPV6)
+		dev_set_name(&iface->dev, "ipv6-iface-%u-%u", shost->host_no,
+			     iface_num);
+	else
+		goto free_iface;
+
+	err = device_register(&iface->dev);
+	if (err)
+		goto free_iface;
+
+	if (iface_type == IFACE_TYPE_IPV4)
+		err = sysfs_create_group(&iface->dev.kobj,
+					 &iscsi_ipv4_iface_group);
+	else if (iface_type == IFACE_TYPE_IPV6)
+		err = sysfs_create_group(&iface->dev.kobj,
+					 &iscsi_ipv6_iface_group);
+
+	if (err)
+		goto iface_unregister_dev;
+
+	if (dd_size)
+		iface->dd_data = &iface[1];
+	return iface;
+
+iface_unregister_dev:
+	idr_remove(&iscsi_iface_idr, id);
+	device_unregister(&iface->dev);
+
+free_iface:
+	kfree(iface);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_iface);
+
+void iscsi_destroy_iface(struct iscsi_iface *iface)
+{
+	if (iface->iface_type == IFACE_TYPE_IPV6)
+		sysfs_remove_group(&iface->dev.kobj, &iscsi_ipv6_iface_group);
+	else
+		sysfs_remove_group(&iface->dev.kobj, &iscsi_ipv4_iface_group);
+
+	idr_remove(&iscsi_iface_idr, iface->id);
+	device_unregister(&iface->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
+
+struct iscsi_iface *iscsi_lookup_iface(int handle)
+{
+	struct iscsi_iface *iface;
+
+	iface = idr_find(&iscsi_iface_idr, handle);
+
+	return iface;
+}
+EXPORT_SYMBOL_GPL(iscsi_lookup_iface);
+
+
+/* end */
+
+
 static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
 			    struct device *cdev)
 {
@@ -2175,6 +2360,27 @@ iscsi_register_transport(struct iscsi_transport *tt)
 
 	BUG_ON(count > ISCSI_SESSION_ATTRS);
 	priv->session_attrs[count] = NULL;
+	count = 0;
+
+	SETUP_IPV4_IFACE_RD_ATTR(ipaddress, ISCSI_NET_IPV4_ADDR);
+	SETUP_IPV4_IFACE_RD_ATTR(gateway, ISCSI_NET_IPV4_ADDR);
+	SETUP_IPV4_IFACE_RD_ATTR(bootproto, ISCSI_NET_IPV4_ADDR);
+	SETUP_IPV4_IFACE_RD_ATTR(subnet, ISCSI_NET_IPV4_ADDR);
+	SETUP_IPV4_IFACE_RD_ATTR(state, ISCSI_NET_IPV4_ADDR);
+	BUG_ON(count > ISCSI_IPV4_IFACE_ATTRS);
+	iscsi_ipv4_iface_attrs[count] = NULL;
+	count = 0;
+
+	SETUP_IPV6_IFACE_RD_ATTR(ipaddress, ISCSI_NET_IPV6_ADDR);
+	SETUP_IPV6_IFACE_RD_ATTR(link_local_addr, ISCSI_NET_IPV6_LINKLOCAL);
+	SETUP_IPV6_IFACE_RD_ATTR(router_addr, ISCSI_NET_IPV6_ROUTER);
+	SETUP_IPV6_IFACE_RD_ATTR(ipaddr_autocfg,
+				 ISCSI_NET_IPV6_ADDR_AUTOCFG);
+	SETUP_IPV6_IFACE_RD_ATTR(linklocal_autocfg,
+				 ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG);
+	SETUP_IPV6_IFACE_RD_ATTR(state, ISCSI_NET_IFACE_STATE);
+	BUG_ON(count > ISCSI_IPV6_IFACE_ATTRS);
+	iscsi_ipv6_iface_attrs[count] = NULL;
 
 	spin_lock_irqsave(&iscsi_transport_lock, flags);
 	list_add(&priv->list, &iscsi_transports);
@@ -2237,10 +2443,14 @@ static __init int iscsi_transport_init(void)
 	if (err)
 		goto unregister_transport_class;
 
-	err = transport_class_register(&iscsi_host_class);
+	err = class_register(&iscsi_iface_class);
 	if (err)
 		goto unregister_endpoint_class;
 
+	err = transport_class_register(&iscsi_host_class);
+	if (err)
+		goto unregister_iface_class;
+
 	err = transport_class_register(&iscsi_connection_class);
 	if (err)
 		goto unregister_host_class;
@@ -2270,6 +2480,8 @@ unregister_conn_class:
 	transport_class_unregister(&iscsi_connection_class);
 unregister_host_class:
 	transport_class_unregister(&iscsi_host_class);
+unregister_iface_class:
+	class_unregister(&iscsi_iface_class);
 unregister_endpoint_class:
 	class_unregister(&iscsi_endpoint_class);
 unregister_transport_class:
@@ -2285,6 +2497,7 @@ static void __exit iscsi_transport_exit(void)
 	transport_class_unregister(&iscsi_session_class);
 	transport_class_unregister(&iscsi_host_class);
 	class_unregister(&iscsi_endpoint_class);
+	class_unregister(&iscsi_iface_class);
 	class_unregister(&iscsi_transport_class);
 }
 
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 312b495..a55ee82 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -272,6 +272,23 @@ enum iscsi_net_param_type {
 	ISCSI_NET_PARAM_IFACE_STATE	= 13,
 };
 
+#define ISCSI_NET_IPV4_ADDR		(1ULL << ISCSI_NET_PARAM_IPV4_ADDR)
+#define ISCSI_NET_IPV4_SUBNET		(1ULL << ISCSI_NET_PARAM_IPV4_SUBNET)
+#define ISCSI_NET_IPV4_GW		(1ULL << ISCSI_NET_PARAM_IPV4_GW)
+#define ISCSI_NET_IPV4_BOOTPROTO	(1ULL << ISCSI_NET_PARAM_IPV4_BOOTPROTO)
+#define ISCSI_NET_VLAN			(1ULL << ISCSI_NET_PARAM_VLAN)
+#define ISCSI_NET_MAC			(1ULL << ISCSI_NET_PARAM_MAC)
+#define ISCSI_NET_IPV6_LINKLOCAL	(1ULL << ISCSI_NET_PARAM_IPV6_LINKLOCAL)
+#define ISCSI_NET_IPV6_ADDR		(1ULL << ISCSI_NET_PARAM_IPV6_ADDR)
+#define ISCSI_NET_IPV6_ROUTER		(1ULL << ISCSI_NET_PARAM_IPV6_ROUTER)
+#define ISCSI_NET_IPV6_AUTOCFG		(1ULL << ISCSI_NET_PARAM_IPV6_AUTOCFG)
+#define ISCSI_NET_IPV6_ADDR_AUTOCFG			\
+				(1ULL << ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG)
+#define ISCSI_NET_IPV6_LINKLOCAL_AUTOCFG		\
+				(1ULL << ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG)
+#define ISCSI_NET_IFACE_STATE		(1ULL << ISCSI_NET_PARAM_IFACE_STATE)
+
+
 /* 20 param per iface * 10 iface per port = 200 params */
 #define ISCSI_MAX_IFACE_PER_HW		10
 #define ISCSI_MAX_PARAM_PER_IFACE	20
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 45b9df9..29d314a 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -37,6 +37,7 @@ struct iscsi_cls_conn;
 struct iscsi_conn;
 struct iscsi_task;
 struct sockaddr;
+struct iscsi_iface;
 
 /**
  * struct iscsi_transport - iSCSI Transport template
@@ -87,6 +88,8 @@ struct iscsi_transport {
 	/* LLD sets this to indicate what values it can export to sysfs */
 	uint64_t param_mask;
 	uint64_t host_param_mask;
+	uint64_t ipv4_iface_param_mask;
+	uint64_t ipv6_iface_param_mask;
 	struct iscsi_cls_session *(*create_session) (struct iscsi_endpoint *ep,
 					uint16_t cmds_max, uint16_t qdepth,
 					uint32_t sn);
@@ -138,6 +141,8 @@ struct iscsi_transport {
 			  uint32_t enable, struct sockaddr *dst_addr);
 	int (*set_path) (struct Scsi_Host *shost, struct iscsi_path *params);
 	int (*set_net_config) (struct Scsi_Host *shost, char *data, int count);
+	int (*get_iface_param) (struct iscsi_iface *iface,
+				enum iscsi_net_param_type param, char *buf);
 };
 
 /*
@@ -229,6 +234,20 @@ struct iscsi_endpoint {
 	struct iscsi_cls_conn *conn;
 };
 
+struct iscsi_iface {
+	struct device dev;
+	struct iscsi_transport *transport;
+	uint64_t id;
+	uint32_t iface_type;	/* IPv4 or IPv6 */
+	uint32_t iface_num;	/* iface number, 0 - n */
+	void *dd_data;		/* LLD private data */
+};
+
+#define iscsi_dev_to_iface(_dev) \
+	container_of(_dev, struct iscsi_iface, dev)
+#define iscsi_iface_to_shost(_iface) \
+	dev_to_shost(_iface->dev.parent)
+
 /*
  * session and connection functions that can be used by HW iSCSI LLDs
  */
@@ -262,5 +281,10 @@ extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size);
 extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep);
 extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle);
 extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd);
+extern struct iscsi_iface *iscsi_create_iface(struct Scsi_Host *shost,
+			struct iscsi_transport *transport, uint32_t iface_type,
+			uint32_t iface_num, int dd_size);
+extern void iscsi_destroy_iface(struct iscsi_iface *iface);
+extern struct iscsi_iface *iscsi_lookup_iface(int handle);
 
 #endif
-- 
1.7.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux