From deef9e20c2f1b107760b5b4c29289de77fcdc39f Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Sun, 14 Aug 2011 01:50:13 -0500 Subject: [PATCH] iscsiadm: add netconfig support 1. Current status: Using iscsiadm one cannot do any network configuration for qla4xxx adapters. However an iface is created for the qla4xxx ports using the hwaddress. \# ls /etc/iscsi/ifaces/ iface.example iface0 qla4xxx.00:0e:1e:04:8b:2a qla4xxx.00:0e:1e:04:8b:2e This allows user to issue sendtargets via the qla4xxx iscsi offload. 2. Current Proposal: Current proposal is to allow iscsiadm to configure the network settings for qla4xxx ports. This implementation is based on discussions at - http://marc.info/?l=linux-scsi&m=127066184916180&w=2 - http://groups.google.com/group/open-iscsi/browse_thread/thread/d8e8c2df71c95d69/8f731d95d46141a0?lnk=gst&q=iscsi+hba# 2.1 Changes in iscsiadm/iscsid 2.1.1 Add a new event: ISCSI_UEVENT_SET_IFACE_PARAMS 2.1.2 New structure/enum to represent a single network parameter - enum iscsi_net_param; - struct iscsi_iface_param_info; 2.1.3 Added new parameters in iface 2.1.4 Change in operations Add two new operations to iscsiadm apply: Apply the single iface settings applyall: Apply the iface settings of all iface having the same MAC address 2.2 Changes in sysfs network representation The new sysfs directory would look like this:- /sys/class/iscsi_iface/-| _______________________| | |- ipv4-iface--/ <-- for ipv4 |- bootproto |- enabled |- ipaddress |- subnet |- gateway |- mtu |- port |- vlan |- vlan_enabled |- vlan_priority |- ipv6-iface--/ <-- for ipv6 |- enabled |- ipaddr_autocfg |- ipaddress |- link_local_addr |- linklocal_autocfg |- mtu |- port |- router_addr |- vlan |- vlan_enabled |- vlan_priority 3. Flow: 3.1 User space code: - If user specify --op=update, then just update the iface config file - If use specify --op=applyall then ifaces for the host passed in. and build up the net config buffer. - Note: If --op is "apply" then only settings for single iface is read, the iface provided with -I option is only read. - The net config buffer will look like this. ----------------------------------------------------------------| | iscsi_net_param { | | iface_num = 0; | | len = 4; | | param = ISCSI_NET_PARAM_IPV4_ADDR; | | iface_type = ISCSI_IFACE_TYPE_IPV4; | | param_type = ISCSI_NET_PARAM; | | value[0] = ipaddress[0]; | | value[1] = ipaddress[1]; | | value[2] = ipaddress[2]; | | value[3] = ipaddress[3]; | | } | ----------------------------------------------------------------| | iscsi_net_param { | | iface_num = 0; | | len = 4; | | param = ISCSI_NET_PARAM_IPV4_GW; | | iface_type = ISCSI_IFACE_TYPE_IPV4; | | param_type = ISCSI_NET_PARAM; | | value[0] = ipgateway[0]; | | value[1] = ipgateway[1]; | | value[2] = ipgateway[2]; | | value[3] = ipgateway[3]; | | } | ----------------------------------------------------------------- | | | iscsi_net_param { | | iface_num = 1; | | len = 4; | | param = ISCSI_NET_PARAM_IPV4_ADDR; | | iface_type = ISCSI_IFACE_TYPE_IPV4; | | param_type = ISCSI_NET_PARAM; | | value[0] = ipaddress[0]; | | value[1] = ipaddress[1]; | | value[2] = ipaddress[2]; | | value[3] = ipaddress[3]; | | } | ----------------------------------------------------------------- ----------------------------------------------------------------- | iscsi_net_param { | | iface_num = 0; | | len = 4; | | param = ISCSI_NET_PARAM_IPV4_GW; | | iface_type = ISCSI_IFACE_TYPE_IPV4; | | param_type = ISCSI_NET_PARAM; | | value[0] = ipgateway[0]; | | value[1] = ipgateway[1]; | | value[2] = ipgateway[2]; | | value[3] = ipgateway[3]; | | } | ----------------------------------------------------------------- | iscsi_net_param { | | iface_num = 1; | | len = 1; | | param = ISCSI_NET_PARAM_IFACE_ENABLED; | | iface_type = ISCSI_IFACE_TYPE_IPV4; | | param_type = ISCSI_NET_PARAM; | | offset = 0; | | value[0] = 0; /* 0 = disable, default = 1 = enable */ | | } | ----------------------------------------------------------------- Each netconfig parameter has different size requirement for value field. e.g.: IPv4 address requires 4 bytes, IPv6 address requires 16 bytes etc. The memory allocated for each netconfig parameter is size of iscsi_net_param + length required for that parameter. The multiple IO Vector mechanism is used to send netconfig parameter from user space to kernel using Netlink interface. IO Vector 0 is used for Netlink message header. IO Vector 1 is used for iSCSI User Event (ev). - The ev will be sent down with event type = ISCSI_UEVENT_SET_NET_CONFIG IO Vector 2 onwards, each vector consists of the struct iscsi_net_param with parameter name followed by its value. The total size will be addition of all the IO vector sizes. 3.2 Kernel space code: - Once event is received, the buffer will look like struct iscsi_net_param with parameter name followed by its value, then next parameter and its value and so on. - the scsi_transport_iscsi would call the adapter's transport->set_net_config - In set_net_config each individual param can be decoded and set into the hardware. 4. qla4xxx configuration: iscsid, creates the iface for qla4xxx, based on the hwaddress. To display the iface related to qla4xxx execute following \# iscsiadm -m iface qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,,, qla4xxx.00:0e:1e:04:8b:2e.ipv6 qla4xxx,00:0e:1e:04:8b:2e,,, qla4xxx.00:0e:1e:04:8b:2a qla4xxx,00:0e:1e:04:8b:2a,20.15.0.66,, qla4xxx.00:0e:1e:04:8b:2a.ipv6 qla4xxx,00:0e:1e:04:8b:2a,2001:DB8:1111:2222::8888,, qla4xxx.00:0e:1e:04:8b:2a.ipv6.1 qla4xxx,00:0e:1e:04:8b:2a,2001:DB8:4444:5555::9999,, To setup network configuration there can be two methods 4. 1. User can manually modify the iface file, and issue an "apply" command. --------------------------------------------------------------------------- \#cat /etc/iscsi/ifaces/ iface.example iface0 qla4xxx.00:0e:1e:04:8b:2a qla4xxx.00:0e:1e:04:8b:2e Example: \# cat qla4xxx.00:0e:1e:04:8b:2a iface.iscsi_ifacename = qla4xxx.00:0e:1e:04:8b:2a iface.transport_name = qla4xxx iface.hwaddress = 00:0e:1e:04:8b:2a iface.state = enable iface.iface_num = 0 (default) iface.bootproto = static iface.ipaddress = 192.168.2.2 (decimal) iface.subnetmask = 255.255.255.0 (decimal) \# vi qla4xxx.00:0e:1e:04:8b:2a.ipv6 (If file does not exist, the one can create it) iface.iscsi_ifacename = qla4xxx.00:0e:1e:04:8b:2a.ipv6 iface.transport_name = qla4xxx iface.hwaddress = 00:0e:1e:04:8b:2a iface.ipaddress = 1111:2222::7777:8888 (hex) iface.iface_num = 0 \# iscsiadm -m iface -H 00:0e:1e:04:8b:2a --op=applyall This will find the ifaces on the host with MAC address 00:0e:1e:04:8b:2a and apply the settings to the hardware.. Note, this will read all the iface belonging to the same MAC address. Note2, Instead of a MAC address the host number can be passed in. 4.2. User can use iscsiadm to specify the values and then apply -------------------------------------------------------------- \# ls /etc/iscsi/ifaces/ iface.example iface0 qla4xxx.00:0e:1e:04:8b:2a qla4xxx.00:0e:1e:04:8b:2e \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ -n iface.ipaddress -v 192.168.1.2 \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ -n iface.gateway -v 192.168.1.1 \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ -n iface.subnet_mask -v 255.255.255.0 \# iscsiadm -m iface -H 00:0e:1e:04:8b:2a -o applyall Setting up multiple IP: First interface (default, no need to set iface_num, it is 0 by default) \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ -n iface.ipaddress -v 192.168.1.2 Create the second one if it does not exist \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a.1 -op=new \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ -n iface.iface_num -v 1 (Mandatory) \# iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ -n iface.ipaddress -v 192.168.1.3 \# iscsiadm -m iface -H 00:0e:1e:04:8b:2a --op=applyall Note: If there are common settings for multiple interfaces then the settings from 0th iface would be considered valid. Note: To apply settings for a single iface, just say --op=apply Signed-off-by: Lalit Chandivade Signed-off-by: Harish Zunjarrao [formatting fixes and addition of host param for applyall] Signed-off-by: Mike Christie Signed-off-by: Vikas Chaudhary --- README | 48 ++- doc/iscsiadm.8 | 20 +- etc/iface.example | 135 +++++++ include/iscsi_if.h | 83 ++++- usr/config.h | 17 + usr/idbm.c | 57 +++ usr/idbm.h | 2 + usr/idbm_fields.h | 13 +- usr/iface.c | 822 +++++++++++++++++++++++++++++++++++++++++- usr/iface.h | 4 + usr/iscsi_ipc.h | 3 + usr/iscsi_sysfs.c | 2 +- usr/iscsiadm.c | 188 +++++++++- usr/netlink.c | 168 ++++++--- utils/fwparam_ibft/fw_entry.c | 2 +- 15 files changed, 1482 insertions(+), 82 deletions(-) diff --git a/README b/README index ee69002..9f24659 100644 --- a/README +++ b/README @@ -371,9 +371,10 @@ Usage: iscsiadm [OPTION] iscsi_ifacename. See below for examples. - -m host --host=hostno --print=level - Display information for a specific host if hostno - is passed in. If no hostno is passed in then info + -m host --host=hostno|MAC --print=level + Display information for a specific host. The host + can be passed in by host number or by MAC address. + If a host is not passed in then info for all hosts is printed. Print level can be 0 to 4. @@ -515,10 +516,10 @@ some helpful management commands. 5.1.2 Setting up a iface for a iSCSI offload card ================================================= -This section describes how to setup ifaces for use with Chelsio -and Broadcom cards. +This section describes how to setup ifaces for use with Chelsio, Broadcom and +QLogic cards. -By default, iscsiadm will create a iface for each Broadcom and Chelsio +By default, iscsiadm will create a iface for each Broadcom, QLogic and Chelsio port. The iface name will be of the form: $transport/driver_name.$MAC_ADDRESS @@ -529,6 +530,7 @@ Running: default tcp,,,, iser iser,,,, cxgb3i.00:07:43:05:97:07 cxgb3i,00:07:43:05:97:07,,, +qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,,, Will report iface configurations that are setup in /etc/iscsi/ifaces. @@ -547,7 +549,7 @@ default one in /etc/iscsi/initiatorname.iscsi. -To display these values in a more friendly run: +To display these values in a more friendly way, run: iscsiadm -m iface -I cxgb3i.00:07:43:05:97:07 # BEGIN RECORD 2.0-871 @@ -571,6 +573,38 @@ For the name of the value we want to update we use the name from the "iscsiadm -m iface -I cxgb3i.00:07:43:05:97:07" command which is "iface.ipaddress". +Note2. + +For QLogic ports after updating the iface record, for network settings to take +effect, one must apply or applyall the settings. + +iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2e -o apply or +iscsiadm -m iface -H 00:0e:1e:04:8b:2e -o applyall + +With operation "apply" network setting for the specified iface will take effect. +With operation "applyall" network settings for all ifaces on a specific host +will take take effect. The host can be specified using the -H/--host argument +by either the MAC address of the host or the host number. + + +Here is an example of setting multiple IPv6 address on single iSCSI interface +port. +First interface (no need to set iface_num, it is 0 by default) + +iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ + -n iface.ipaddress -v fec0:ce00:7014:0041:1111:2222:1e04:9392 + +Create the second interface if it does not exist + +iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a.1 -op=new +iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ + -n iface.iface_num -v 1 (iface_num is mandatory for second iface) +iscsiadm -m iface -I qla4xxx.00:0e:1e:04:8b:2a -o update \ + -n iface.ipaddress -v = fec0:ce00:7014:0041:1111:2222:1e04:9393 +iscsiadm -m iface -H 00:0e:1e:04:8b:2a --op=applyall + +Note: If there are common settings for multiple interfaces then the +settings from 0th iface would be considered valid. Now, we can use this iface to login into targets, which is described in the next section. diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 index b41281a..a036142 100644 --- a/doc/iscsiadm.8 +++ b/doc/iscsiadm.8 @@ -12,11 +12,11 @@ iscsiadm \- open-iscsi administration utility \fBiscsiadm\fR \-m session [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-r sessionid | sysfsdir [ \-R ] [ \-u | \-s | \-o new ] ] -\fBiscsiadm\fR \-m iface [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I ifacename ] [ [ \-o operation ] [ \-n name ] [ \-v value ] ] +\fBiscsiadm\fR \-m iface [ \-hV ] [ \-d debug_level ] [ \-P printlevel ] [ \-I ifacename | \-H hostno|MAC ] [ [ \-o operation ] [ \-n name ] [ \-v value ] ] \fBiscsiadm\fR \-m fw [\-l] -\fBiscsiadm\fR \-m host [ \-P printlevel ] [ \-H hostno ] +\fBiscsiadm\fR \-m host [ \-P printlevel ] [ \-H hostno|MAC ] \fBiscsiadm\fR \-k priority @@ -49,10 +49,10 @@ print debugging information. Valid values for debug_level are 0 to 8. display help text and exit .TP -\fB\-H\fR, \fB\-\-host=\fI[hostno]\fR -The host agrument specifies the SCSI host to use for the operation. The -hostno value is the host number assigned to the host by the kernel's -scsi layer. +\fB\-H\fR, \fB\-\-host=\fI[hostno|MAC]\fR +The host agrument specifies the SCSI host to use for the operation. It can be +the scsi host number assigned to the host by the kernel's scsi layer, or the +MAC address of a scsi host. .TP \fB\-I\fR, \fB\-\-interface=\fI[iface]\fR @@ -147,6 +147,8 @@ operator. Specifies a database operator \fIop\fR. \fIop\fR must be one of \fInew\fR, \fIdelete\fR, \fIupdate\fR, \fIshow\fR or \fInonpersistent\fR. .IP +For iface mode, \fIapply\fR and \fIapplyall\fR are also applicable. +.IP This option is valid for all modes except fw. Delete should not be used on a running session. If it is iscsiadm will stop the session and then delete the record. .IP @@ -170,6 +172,12 @@ sid is passed in. .IP \fInonpersistent\fR instructs iscsiadm to not manipulate the node DB. +.IP +\fIapply\fR will cause the network settings to take effect on the specified iface. + +.IP +\fIapplyall\fR will cause the network settings to take effect on all the ifaces whose MAC address or host number matches that of the specific host. + .TP \fB\-p\fR, \fB\-\-portal=\fIip[:port]\fR Use target portal with ip-address \fIip\fR and \fIport\fR. If port is not passed diff --git a/etc/iface.example b/etc/iface.example index 3c7354f..7af784b 100644 --- a/etc/iface.example +++ b/etc/iface.example @@ -60,3 +60,138 @@ # the same subnet. # iface.net_ifacename = eth0 # iface.ipaddress = 102.50.50.101 + +# OPTIONAL: iface.bootproto +# +# Valid values are: +# "dhcp" and "static" +# +# REQUIRED when IPv4 address need to be obtained dynamically using DHCP +# example: +# iface.bootproto = dhcp +# +# OPTIONAL when the IPv4 address is set statically +# example: +# iface.ipaddress = 102.50.50.101 +# iface.bootproto = static +# + +# OPTIONAL: iface.vlan_id +# Used to set the VLAN ID for the iSCSI interfae. +# example +# iface.vlan_id = 1022 + +# OPTIONAL: iface.vlan_priority +# Used to set the VLAN priority for the iSCSI interfae. +# example +# iface.vlan_priority = 1 + +# OPTIONAL: iface.vlan_state +# Used to enable or disable the VLAN on the iSCSI interface +# example +# iface.vlan_state = enable + +# OPTIONAL: iface.ipv6_linklocal +# Specify the IPV6 Link Local Address with the +# link local prefix of FE80::0/64 +# example: +# iface.ipv6_linklocal = fe80:0000:0000:0000:020e:1eff:1111:2221 + +# OPTIONAL: iface.ipv6_router +# Used to set a default IPV6 router +# example: +# iface.ipv6_router = fe80:0000:0000:0000:7ae7:d1ff:fe72:4048 + +# OPTIONAL: iface.ipv6_autocfg +# Used to set the discovery protocol to obtain IPV6 address +# For example qla4xxx support neighbor discovery +# example: +# iface.ipv6_autocfg = nd + +# OPTIONAL: iface.linklocal_autocfg +# For transport like qla4xxx this allows to auto configure the +# IPV6 link local address based on the MAC address of the iSCSI +# interface + +# OPTIONAL: iface.router_autocfg +# Required to set the IPv6 router discovery protocol +# To set the router discovery protocol to Neighbor Discovery specify "nd" +# example: +# iface.router_autocfg = nd + +# OPTIONAL: iface.state +# By default the iface is enabled +# iface.state = enable +# To disable the iface set the state to "disable" +# iface.state = disable + +# iface.iface_num +# REQUIRED: When there are more than 1 interface to be configured. +# For transports like qla4xxx, one can specify two IPV6 interfaces +# in such case the iface_num must be set correctly +# example: +# iface settings for first IPV6 interface +# iface.iscsi_ifacename = iface-qla4xxx-ipv6-1 +# iface.iface_num = 0 +# +# iface settings for second IPV6 interface +# iface.iscsi_ifacename = iface-qla4xxx-ipv6-2 +# iface.iface_num = 1 + +# Here are some example iface files +# IPV4 sample config file with static IP address: +# BEGIN RECORD 2.0-872 +# iface.iscsi_ifacename = qla4xxx-3 +# iface.ipaddress = 192.168.1.75 +# iface.hwaddress = 00:0e:1e:04:93:92 +# iface.transport_name = qla4xxx +# iface.bootproto = static +# iface.subnet_mask = 255.255.255.0 +# iface.gateway = 192.168.1.1 +# iface.state = enable +# iface.vlan = +# iface.iface_num = 0 +# END RECORD +# +# IPV6 sample config file with neighbor discovery: +# BEGIN RECORD 2.0-872 +# iface.iscsi_ifacename = qla4xxx-3-1 +# iface.ipaddress = +# iface.hwaddress = 00:0e:1e:04:93:92 +# iface.transport_name = qla4xxx +# iface.ipv6_autocfg = nd +# iface.linklocal_autocfg = auto +# iface.router_autocfg = nd +# iface.ipv6_linklocal = fe80:0000:0000:0000:020e:1eff:1111:2221 +# iface.ipv6_router = auto +# iface.state = enable +# iface.vlan = +# iface.iface_num = 0 +# END RECORD + +# Ipv4 sample config file (DHCP configuration): +# BEGIN RECORD 2.0-872 +# iface.iscsi_ifacename = qla4xxx-3 +# iface.hwaddress = 00:0e:1e:04:93:92 +# iface.transport_name = qla4xxx +# iface.bootproto = dhcp +# iface.state = enable +# iface.vlan = +# iface.iface_num = 0 +# END RECORD + +# Sample ipv6 config file(manual configured IPs): +# BEGIN RECORD 2.0-872 +# iface.iscsi_ifacename = iface-new-file +# iface.ipaddress = fec0:ce00:7014:0041:1111:2222:1e04:9392 +# iface.hwaddress = 00:0e:1e:04:93:92 +# iface.transport_name = qla4xxx +# iface.ipv6_autocfg = +# iface.linklocal_autocfg = +# iface.router_autocfg = +# iface.ipv6_linklocal = fe80:0000:0000:0000:0000:0000:1e04:9392 +# iface.ipv6_router = fe80:0000:0000:0000:7ae7:d1ff:fe72:4048 +# iface.state = enable +# iface.vlan = +# iface.iface_num = 0 +# END RECORD diff --git a/include/iscsi_if.h b/include/iscsi_if.h index 50a09cb..72d4c41 100644 --- a/include/iscsi_if.h +++ b/include/iscsi_if.h @@ -64,8 +64,9 @@ enum iscsi_uevent_e { ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST = UEVENT_BASE + 19, ISCSI_UEVENT_PATH_UPDATE = UEVENT_BASE + 20, + ISCSI_UEVENT_SET_IFACE_PARAMS = UEVENT_BASE + 21, - ISCSI_UEVENT_MAX = ISCSI_UEVENT_PATH_UPDATE, + ISCSI_UEVENT_MAX = ISCSI_UEVENT_SET_IFACE_PARAMS, /* up events */ ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, @@ -181,6 +182,10 @@ struct iscsi_uevent { struct msg_set_path { uint32_t host_no; } set_path; + struct msg_set_iface_params { + uint32_t host_no; + uint32_t count; + } set_iface_params; } u; union { /* messages k -> u */ @@ -223,6 +228,21 @@ struct iscsi_uevent { } r; } __attribute__ ((aligned (sizeof(uint64_t)))); +enum iscsi_param_type { + ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */ + ISCSI_HOST_PARAM, /* iscsi_host_param */ + ISCSI_NET_PARAM, /* iscsi_net_param */ +}; + +struct iscsi_iface_param_info { + uint32_t iface_num; /* iface number, 0 - n */ + uint32_t len; /* Actual length of the param */ + uint16_t param; /* iscsi param value */ + uint8_t iface_type; /* IPv4 or IPv6 */ + uint8_t param_type; /* iscsi_param_type */ + uint8_t value[0]; /* length sized value follows */ +} __packed; + /* * To keep the struct iscsi_uevent size the same for userspace code * compatibility, the main structure for ISCSI_UEVENT_PATH_UPDATE and @@ -246,6 +266,60 @@ struct iscsi_path { uint16_t pmtu; } __attribute__ ((aligned (sizeof(uint64_t)))); +/* iscsi iface enabled/disabled setting */ +#define ISCSI_IFACE_DISABLE 0x01 +#define ISCSI_IFACE_ENABLE 0x02 + +/* ipv4 bootproto */ +#define ISCSI_BOOTPROTO_STATIC 0x01 +#define ISCSI_BOOTPROTO_DHCP 0x02 + +/* ipv6 addr autoconfig type */ +#define ISCSI_IPV6_AUTOCFG_DISABLE 0x01 +#define ISCSI_IPV6_AUTOCFG_ND_ENABLE 0x02 +#define ISCSI_IPV6_AUTOCFG_DHCPV6_ENABLE 0x03 + +/* ipv6 link local addr type */ +#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE 0x01 +#define ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE 0x02 + +/* ipv6 router addr type */ +#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 + +#define ISCSI_MAX_VLAN_ID 4095 +#define ISCSI_MAX_VLAN_PRIORITY 7 + +/* iscsi vlan enable/disabled setting */ +#define ISCSI_VLAN_DISABLE 0x01 +#define ISCSI_VLAN_ENABLE 0x02 + +/* iSCSI network params */ +enum iscsi_net_param { + ISCSI_NET_PARAM_IPV4_ADDR = 1, + ISCSI_NET_PARAM_IPV4_SUBNET = 2, + ISCSI_NET_PARAM_IPV4_GW = 3, + ISCSI_NET_PARAM_IPV4_BOOTPROTO = 4, + ISCSI_NET_PARAM_MAC = 5, + ISCSI_NET_PARAM_IPV6_LINKLOCAL = 6, + ISCSI_NET_PARAM_IPV6_ADDR = 7, + ISCSI_NET_PARAM_IPV6_ROUTER = 8, + ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG = 9, + ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG = 10, + ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG = 11, + ISCSI_NET_PARAM_IFACE_ENABLE = 12, + ISCSI_NET_PARAM_VLAN_ID = 13, + ISCSI_NET_PARAM_VLAN_PRIORITY = 14, + ISCSI_NET_PARAM_VLAN_ENABLED = 15, + ISCSI_NET_PARAM_IFACE_TYPE = 16, + ISCSI_NET_PARAM_IFACE_NAME = 17, + ISCSI_NET_PARAM_MTU = 18, + ISCSI_NET_PARAM_PORT = 19, +}; + /* * Common error codes */ @@ -272,6 +346,7 @@ enum iscsi_err { ISCSI_ERR_INVALID_HOST = ISCSI_ERR_BASE + 18, ISCSI_ERR_XMIT_FAILED = ISCSI_ERR_BASE + 19, ISCSI_ERR_TCP_CONN_CLOSE = ISCSI_ERR_BASE + 20, + ISCSI_ERR_SCSI_EH_SESSION_RST = ISCSI_ERR_BASE + 21, }; /* @@ -300,7 +375,7 @@ enum iscsi_param { ISCSI_PARAM_PERSISTENT_PORT, ISCSI_PARAM_SESS_RECOVERY_TMO, - /* pased in through bind conn using transport_fd */ + /* passed in through bind conn using transport_fd */ ISCSI_PARAM_CONN_PORT, ISCSI_PARAM_CONN_ADDRESS, @@ -322,6 +397,7 @@ enum iscsi_param { ISCSI_PARAM_INITIATOR_NAME, ISCSI_PARAM_TGT_RESET_TMO, + ISCSI_PARAM_TARGET_ALIAS, /* must always be last */ ISCSI_PARAM_MAX, }; @@ -362,6 +438,7 @@ enum iscsi_param { #define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID) #define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME) #define ISCSI_TGT_RESET_TMO (1ULL << ISCSI_PARAM_TGT_RESET_TMO) +#define ISCSI_TARGET_ALIAS (1ULL << ISCSI_PARAM_TARGET_ALIAS) /* iSCSI HBA params */ enum iscsi_host_param { @@ -390,7 +467,7 @@ enum iscsi_host_param { #define CAP_HDRDGST 0x10 #define CAP_DATADGST 0x20 #define CAP_MULTI_CONN 0x40 -#define CAP_TEXT_NEGO 0x80 /* support for text requests */ +#define CAP_TEXT_NEGO 0x80 #define CAP_MARKERS 0x100 #define CAP_FW_DB 0x200 #define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */ diff --git a/usr/config.h b/usr/config.h index 0d475c2..9174f2c 100644 --- a/usr/config.h +++ b/usr/config.h @@ -204,14 +204,31 @@ typedef struct session_rec { } session_rec_t; #define ISCSI_TRANSPORT_NAME_MAXLEN 16 +#define ISCSI_MAX_STR_LEN 80 typedef struct iface_rec { struct list_head list; /* 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; /* * TODO: we may have to make this bigger and interconnect * specific for infinniband diff --git a/usr/idbm.c b/usr/idbm.c index 875a123..d3383fc 100644 --- a/usr/idbm.c +++ b/usr/idbm.c @@ -72,6 +72,28 @@ static struct idbm *db; _n++; \ } while(0) +#define __recinfo_uint8(_key, _info, _rec, _name, _show, _n, _mod) do { \ + _info[_n].type = TYPE_UINT8; \ + strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ + snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \ + _info[_n].data = &_rec->_name; \ + _info[_n].data_len = sizeof(_rec->_name); \ + _info[_n].visible = _show; \ + _info[_n].can_modify = _mod; \ + _n++; \ +} while (0) + +#define __recinfo_uint16(_key, _info, _rec, _name, _show, _n, _mod) do { \ + _info[_n].type = TYPE_UINT16; \ + strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ + snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \ + _info[_n].data = &_rec->_name; \ + _info[_n].data_len = sizeof(_rec->_name); \ + _info[_n].visible = _show; \ + _info[_n].can_modify = _mod; \ + _n++; \ +} while (0) + #define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \ _info[_n].type = TYPE_INT_O; \ strlcpy(_info[_n].name, _key, NAME_MAXVAL); \ @@ -374,6 +396,27 @@ void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri) __recinfo_str(IFACE_TRANSPORTNAME, ri, r, transport_name, IDBM_SHOW, num, 1); __recinfo_str(IFACE_INAME, ri, r, iname, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_BOOT_PROTO, ri, r, bootproto, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_SUBNET_MASK, ri, r, subnet_mask, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_GATEWAY, ri, r, gateway, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_IPV6_AUTOCFG, ri, r, ipv6_autocfg, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_LINKLOCAL_AUTOCFG, ri, r, linklocal_autocfg, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_ROUTER_AUTOCFG, ri, r, router_autocfg, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_LINKLOCAL, ri, r, ipv6_linklocal, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_ROUTER, ri, r, ipv6_router, IDBM_SHOW, num, 1); + __recinfo_str(IFACE_STATE, ri, r, state, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_VLAN_ID, ri, r, vlan_id, IDBM_SHOW, num, 1); + __recinfo_uint8(IFACE_VLAN_PRIORITY, ri, r, vlan_priority, + IDBM_SHOW, num, 1); + __recinfo_str(IFACE_VLAN_STATE, ri, r, vlan_state, IDBM_SHOW, num, 1); + __recinfo_int(IFACE_NUM, ri, r, iface_num, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_MTU, ri, r, mtu, IDBM_SHOW, num, 1); + __recinfo_uint16(IFACE_PORT, ri, r, port, IDBM_SHOW, num, 1); } recinfo_t *idbm_recinfo_alloc(int max_keys) @@ -518,6 +561,20 @@ setup_passwd_len: *(int*)info[i].data = strtoul(value, NULL, 10); goto updated; + } else if (info[i].type == TYPE_UINT8) { + if (!info[i].data) + continue; + + *(uint8_t *)info[i].data = + strtoul(value, NULL, 10); + goto updated; + } else if (info[i].type == TYPE_UINT16) { + if (!info[i].data) + continue; + + *(uint16_t *)info[i].data = + strtoul(value, NULL, 10); + goto updated; } else if (info[i].type == TYPE_STR) { if (!info[i].data) continue; diff --git a/usr/idbm.h b/usr/idbm.h index 1bcad58..6bca984 100644 --- a/usr/idbm.h +++ b/usr/idbm.h @@ -39,6 +39,8 @@ #define TYPE_INT 0 #define TYPE_INT_O 1 #define TYPE_STR 2 +#define TYPE_UINT8 3 +#define TYPE_UINT16 4 #define MAX_KEYS 256 /* number of keys total(including CNX_MAX) */ #define NAME_MAXVAL 128 /* the maximum length of key name */ #define VALUE_MAXVAL 256 /* the maximum length of 223 bytes in the RFC. */ diff --git a/usr/idbm_fields.h b/usr/idbm_fields.h index 904ccdc..269d87c 100644 --- a/usr/idbm_fields.h +++ b/usr/idbm_fields.h @@ -77,7 +77,18 @@ #define IFACE_GATEWAY "iface.gateway" #define IFACE_PRIMARY_DNS "iface.primary_dns" #define IFACE_SEC_DNS "iface.secondary_dns" -#define IFACE_VLAN "iface.vlan" +#define IFACE_VLAN_ID "iface.vlan_id" +#define IFACE_VLAN_PRIORITY "iface.vlan_priority" +#define IFACE_VLAN_STATE "iface.vlan_state" +#define IFACE_LINKLOCAL "iface.ipv6_linklocal" +#define IFACE_ROUTER "iface.ipv6_router" +#define IFACE_IPV6_AUTOCFG "iface.ipv6_autocfg" +#define IFACE_LINKLOCAL_AUTOCFG "iface.linklocal_autocfg" +#define IFACE_ROUTER_AUTOCFG "iface.router_autocfg" +#define IFACE_STATE "iface.state" +#define IFACE_NUM "iface.iface_num" +#define IFACE_MTU "iface.mtu" +#define IFACE_PORT "iface.port" /* discovery fields */ #define DISC_STARTUP "discovery.startup" diff --git a/usr/iface.c b/usr/iface.c index a0a6389..5d5f7bf 100644 --- a/usr/iface.c +++ b/usr/iface.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "log.h" #include "list.h" @@ -363,7 +364,8 @@ static int __iface_get_by_net_binding(void *data, struct iface_rec *iface) } if (iface_is_bound_by_hwaddr(search->pattern)) { - if (!strcmp(iface->hwaddress, search->pattern->hwaddress)) { + if (!strcasecmp(iface->hwaddress, + search->pattern->hwaddress)) { iface_copy(search->found, iface); return 1; } else @@ -899,3 +901,821 @@ fail: } return rc; } + +struct iface_param_count { + struct iface_rec *primary; + int count; +}; + +/** + * __iface_get_param_count - Gets netconfig parameter count for given iface + * @data: iface_param_count structure + * @iface: iface to setup + */ +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; + int count = 0; + + if (strcmp(iface_params->primary->hwaddress, iface->hwaddress)) + return 0; + + if (strcmp(iface->bootproto, "dhcp") && !strstr(iface->ipaddress, ".")) + iptype = ISCSI_IFACE_TYPE_IPV6; + + if (iptype == ISCSI_IFACE_TYPE_IPV4) { + + if (strcmp(iface->state, "disable")) { + if (strstr(iface->bootproto, "dhcp")) + /* DHCP enabled */ + count++; + else { + /* DHCP disabled */ + count++; + + if (strstr(iface->ipaddress, ".")) { + /* User configured IPv4 Address */ + count++; + + if (strstr(iface->subnet_mask, ".")) + /* User configured Subnet */ + count++; + + if (strstr(iface->gateway, ".")) + /* User configured Gateway */ + count++; + } else + /* + * IPv4 Address not valid, decrement + * count of DHCP + */ + count--; + } + + /* + * If IPv4 configuration in iface file is valid, + * enable state and other parameters (if any) + */ + if (count) { + /* iface state */ + count++; + + if (strcmp(iface->vlan_state, "disable")) { + /* vlan_state enabled */ + count++; + + if (iface->vlan_id) + /* For vlan value */ + count++; + } else + /* vlan_state disabled */ + count++; + + if (iface->mtu) + count++; + + if (iface->port) + count++; + } + } else + /* IPv4 is disabled, iface state */ + count++; + + } else if (iptype == ISCSI_IFACE_TYPE_IPV6) { + + if (strcmp(iface->state, "disable")) { + + /* IPv6 Address */ + if (strstr(iface->ipv6_autocfg, "nd") || + strstr(iface->ipv6_autocfg, "dhcpv6")) + /* Autocfg enabled */ + count++; + else { + /* Autocfg disabled */ + count++; + + if (strstr(iface->ipaddress, ":")) + /* User configured IPv6 Address */ + count++; + else + /* + * IPv6 Address not valid, decrement + * count of IPv6 Autocfg + */ + count--; + } + + /* IPv6 LinkLocal Address */ + if (strstr(iface->linklocal_autocfg, "auto")) + /* Autocfg enabled */ + count++; + else { + /* Autocfg disabled */ + count++; + + if (strstr(iface->ipv6_linklocal, ":")) + /* User configured LinkLocal Address */ + count++; + else + /* + * LinkLocal Address not valid, + * decrement count of LinkLocal Autocfg + */ + count--; + } + + /* IPv6 Router Address */ + if (strstr(iface->router_autocfg, "auto")) + /* Autocfg enabled */ + count++; + else { + /* Autocfg disabled */ + count++; + + if (strstr(iface->ipv6_router, ":")) + /* User configured Router Address */ + count++; + else + /* + * Router Address not valid, + * decrement count of Router Autocfg + */ + count--; + } + + /* + * If IPv6 configuration in iface file is valid, + * enable state and other parameters (if any) + */ + if (count) { + /* iface state */ + count++; + + if (strcmp(iface->vlan_state, "disable")) { + /* vlan_state enabled */ + count++; + + if (iface->vlan_id) + /* For vlan value */ + count++; + } else + /* vlan_state disabled */ + count++; + + if (iface->mtu) + count++; + + if (iface->port) + count++; + } + } else + /* IPv6 is disabled, iface state */ + count++; + } + + iface_params->count += count; + return 0; +} + +/** + * iface_get_param_count - Gets netconfig parameter count from iface + * @iface: iface to setup + * @iface_all: Flag for number of ifaces to traverse (1 for all) + * + * Returns netconfig parameter count. + */ +int iface_get_param_count(struct iface_rec *iface, int iface_all) +{ + int num_found = 0, rc; + struct iface_param_count iface_params; + + log_debug(8, "In iface_get_param_count\n"); + + iface_params.primary = iface; + iface_params.count = 0; + + if (iface_all) + rc = iface_for_each_iface(&iface_params, 0, &num_found, + __iface_get_param_count); + else + rc = __iface_get_param_count(&iface_params, iface); + + log_debug(8, "iface_get_param_count: rc = %d, count = %d\n", + rc, iface_params.count); + return iface_params.count; +} + +/* IPv4/IPv6 Port: 3260 or User defined */ +static int iface_fill_port(struct iovec *iov, struct iface_rec *iface, + uint32_t iface_type) +{ + int len; + struct iscsi_iface_param_info *net_param; + uint16_t port = 3260; + + len = sizeof(struct iscsi_iface_param_info) + 2; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_PORT; + net_param->iface_type = iface_type; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 2; + if (iface->port) + port = iface->port; + memcpy(net_param->value, &port, net_param->len); + return 0; +} + +static int iface_fill_mtu(struct iovec *iov, struct iface_rec *iface, + uint32_t iface_type) +{ + int len; + struct iscsi_iface_param_info *net_param; + uint16_t mtu = 0; + + len = sizeof(struct iscsi_iface_param_info) + 2; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_MTU; + net_param->iface_type = iface_type; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 2; + mtu = iface->mtu; + memcpy(net_param->value, &mtu, net_param->len); + return 0; +} + +/* IPv4/IPv6 VLAN_ID: decimal value <= 4095 */ +static int iface_fill_vlan_id(struct iovec *iov, struct iface_rec *iface, + uint32_t iface_type) +{ + int len; + struct iscsi_iface_param_info *net_param; + uint16_t vlan = 0; + + len = sizeof(struct iscsi_iface_param_info) + 2; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_VLAN_ID; + net_param->iface_type = iface_type; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 2; + if (iface->vlan_id <= ISCSI_MAX_VLAN_ID && + iface->vlan_priority <= ISCSI_MAX_VLAN_PRIORITY) + /* + * Bit 15-13: User Priority of VLAN + * Bit 11-00: VLAN ID + */ + vlan = (iface->vlan_priority << 13) | + (iface->vlan_id & ISCSI_MAX_VLAN_ID); + memcpy(net_param->value, &vlan, net_param->len); + return 0; +} + +/* IPv4/IPv6 VLAN state: disable/enable */ +static int iface_fill_vlan_state(struct iovec *iov, struct iface_rec *iface, + uint32_t iface_type) +{ + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 1; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_VLAN_ENABLED; + net_param->iface_type = iface_type; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 1; + if (strcmp(iface->vlan_state, "disable") && iface->vlan_id) + net_param->value[0] = ISCSI_VLAN_ENABLE; + else /* Assume disabled */ + net_param->value[0] = ISCSI_VLAN_DISABLE; + return 0; +} + +/* IPv4/IPv6 Network state: disable/enable */ +static int iface_fill_net_state(struct iovec *iov, struct iface_rec *iface, + uint32_t iface_type) +{ + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 1; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_IFACE_ENABLE; + net_param->iface_type = iface_type; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 1; + if (!strcmp(iface->state, "disable")) + net_param->value[0] = ISCSI_IFACE_DISABLE; + else /* Assume enabled */ + net_param->value[0] = ISCSI_IFACE_ENABLE; + return 0; +} + +/* IPv4 Bootproto: DHCP/static */ +static int iface_fill_net_bootproto(struct iovec *iov, struct iface_rec *iface) +{ + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 1; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_IPV4_BOOTPROTO; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV4; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 1; + if (!strcmp(iface->bootproto, "dhcp")) + net_param->value[0] = ISCSI_BOOTPROTO_DHCP; + else + net_param->value[0] = ISCSI_BOOTPROTO_STATIC; + return 0; +} + +/* IPv6 IPAddress Autocfg: nd/dhcpv6/disable */ +static int iface_fill_net_autocfg(struct iovec *iov, struct iface_rec *iface) +{ + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 1; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV6; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 1; + + if (!strcmp(iface->ipv6_autocfg, "nd")) + net_param->value[0] = ISCSI_IPV6_AUTOCFG_ND_ENABLE; + else if (!strcmp(iface->ipv6_autocfg, "dhcpv6")) + net_param->value[0] = ISCSI_IPV6_AUTOCFG_DHCPV6_ENABLE; + else + net_param->value[0] = ISCSI_IPV6_AUTOCFG_DISABLE; + + return 0; +} + +/* IPv6 LinkLocal Autocfg: enable/disable */ +static int iface_fill_linklocal_autocfg(struct iovec *iov, + struct iface_rec *iface) +{ + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 1; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV6; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 1; + + if (strstr(iface->linklocal_autocfg, "auto")) + net_param->value[0] = ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE; + else + net_param->value[0] = ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE; + + return 0; +} + +/* IPv6 Router Autocfg: enable/disable */ +static int iface_fill_router_autocfg(struct iovec *iov, struct iface_rec *iface) +{ + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 1; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV6; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 1; + + if (strstr(iface->router_autocfg, "auto")) + net_param->value[0] = ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE; + else + net_param->value[0] = ISCSI_IPV6_ROUTER_AUTOCFG_DISABLE; + + return 0; +} + +/* IPv4 IPAddress/Subnet Mask/Gateway: 4 bytes */ +static int iface_fill_net_ipv4_addr(struct iovec *iov, struct iface_rec *iface, + uint32_t param) +{ + int rc = 1; + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 4; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = param; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV4; + net_param->iface_num = iface->iface_num; + net_param->len = 4; + net_param->param_type = ISCSI_NET_PARAM; + + switch (param) { + case ISCSI_NET_PARAM_IPV4_ADDR: + rc = inet_pton(AF_INET, iface->ipaddress, net_param->value); + if (rc <= 0) + goto free; + break; + case ISCSI_NET_PARAM_IPV4_SUBNET: + rc = inet_pton(AF_INET, iface->subnet_mask, net_param->value); + if (rc <= 0) + goto free; + break; + case ISCSI_NET_PARAM_IPV4_GW: + rc = inet_pton(AF_INET, iface->gateway, net_param->value); + if (rc <= 0) + goto free; + break; + default: + goto free; + } + + /* validate */ + if (!net_param->value[0] && !net_param->value[1] && + !net_param->value[2] && !net_param->value[3]) + goto free; + + return 0; +free: + free(iov->iov_base); + iov->iov_base = NULL; + iov->iov_len = 0; + return 1; +} + +/* IPv6 IPAddress/LinkLocal/Router: 16 bytes */ +static int iface_fill_net_ipv6_addr(struct iovec *iov, struct iface_rec *iface, + uint32_t param) +{ + int rc; + int len; + struct iscsi_iface_param_info *net_param; + + len = sizeof(struct iscsi_iface_param_info) + 16; + iov->iov_base = calloc(len, sizeof(char)); + if (!(iov->iov_base)) + return 1; + + iov->iov_len = len; + net_param = (struct iscsi_iface_param_info *)(iov->iov_base); + net_param->param = param; + net_param->iface_type = ISCSI_IFACE_TYPE_IPV6; + net_param->iface_num = iface->iface_num; + net_param->param_type = ISCSI_NET_PARAM; + net_param->len = 16; + + switch (param) { + case ISCSI_NET_PARAM_IPV6_ADDR: + rc = inet_pton(AF_INET6, iface->ipaddress, net_param->value); + if (rc <= 0) + goto free; + break; + case ISCSI_NET_PARAM_IPV6_LINKLOCAL: + rc = inet_pton(AF_INET6, iface->ipv6_linklocal, + net_param->value); + if (rc <= 0) + goto free; + break; + case ISCSI_NET_PARAM_IPV6_ROUTER: + rc = inet_pton(AF_INET6, iface->ipv6_router, net_param->value); + if (rc <= 0) + goto free; + break; + default: + goto free; + } + + return 0; +free: + free(iov->iov_base); + iov->iov_base = NULL; + iov->iov_len = 0; + return 1; +} + +struct iface_net_config { + struct iface_rec *primary; + struct iovec *iovs; + int count; +}; + +static int __iface_build_net_config(void *data, struct iface_rec *iface) +{ + struct iface_net_config *net_config = data; + struct iovec *iov; + int iptype = ISCSI_IFACE_TYPE_IPV4; + int count = 0; + + if (strcmp(net_config->primary->hwaddress, iface->hwaddress)) + return 0; + + if (strcmp(iface->bootproto, "dhcp") && !strstr(iface->ipaddress, ".")) + iptype = ISCSI_IFACE_TYPE_IPV6; + + /* start at 2, because 0 is for nlmsghdr and 1 for event */ + iov = net_config->iovs + 2; + + if (iptype == ISCSI_IFACE_TYPE_IPV4) { + if (!strcmp(iface->state, "disable")) { + if (!iface_fill_net_state(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV4)) { + net_config->count++; + count++; + } + + return 0; + } + + if (strstr(iface->bootproto, "dhcp")) { + if (!iface_fill_net_bootproto(&iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + } else if (strstr(iface->ipaddress, ".")) { + if (!iface_fill_net_bootproto(&iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + if (!iface_fill_net_ipv4_addr(&iov[net_config->count], + iface, + ISCSI_NET_PARAM_IPV4_ADDR)) { + net_config->count++; + count++; + } + if (strstr(iface->subnet_mask, ".")) { + if (!iface_fill_net_ipv4_addr( + &iov[net_config->count], iface, + ISCSI_NET_PARAM_IPV4_SUBNET)) { + net_config->count++; + count++; + } + } + if (strstr(iface->gateway, ".")) { + if (!iface_fill_net_ipv4_addr( + &iov[net_config->count], iface, + ISCSI_NET_PARAM_IPV4_GW)) { + net_config->count++; + count++; + } + } + } + + /* + * If IPv4 configuration in iface file is valid, + * fill state and other parameters (if any) + */ + if (count) { + if (!iface_fill_net_state(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV4)) { + net_config->count++; + count++; + } + if (!iface_fill_vlan_state(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV4)) { + net_config->count++; + count++; + } + if (strcmp(iface->vlan_state, "disable") && + iface->vlan_id) { + if (!iface_fill_vlan_id(&iov[net_config->count], + iface, ISCSI_IFACE_TYPE_IPV4)) { + net_config->count++; + count++; + } + } + if (iface->mtu) { + if (!iface_fill_mtu(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV4)) { + net_config->count++; + count++; + } + } + if (iface->port) { + if (!iface_fill_port(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV4)) { + net_config->count++; + count++; + } + } + } + } else if (iptype == ISCSI_IFACE_TYPE_IPV6) { + if (!strcmp(iface->state, "disable")) { + if (!iface_fill_net_state(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV6)) { + net_config->count++; + count++; + } + return 0; + } + + /* For IPv6 Address */ + if (strstr(iface->ipv6_autocfg, "nd") || + strstr(iface->ipv6_autocfg, "dhcpv6")) { + if (!iface_fill_net_autocfg(&iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + } else if (strstr(iface->ipaddress, ":")) { + if (!iface_fill_net_autocfg(&iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + /* User provided IPv6 Address */ + if (!iface_fill_net_ipv6_addr(&iov[net_config->count], + iface, + ISCSI_NET_PARAM_IPV6_ADDR)) { + net_config->count++; + count++; + } + } + + /* For LinkLocal Address */ + if (strstr(iface->linklocal_autocfg, "auto")) { + if (!iface_fill_linklocal_autocfg( + &iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + } else if (strstr(iface->ipv6_linklocal, ":")) { + if (!iface_fill_linklocal_autocfg( + &iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + /* User provided Link Local Address */ + if (!iface_fill_net_ipv6_addr(&iov[net_config->count], + iface, + ISCSI_NET_PARAM_IPV6_LINKLOCAL)) { + net_config->count++; + count++; + } + } + + /* For Router Address */ + if (strstr(iface->router_autocfg, "auto")) { + if (!iface_fill_router_autocfg(&iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + } else if (strstr(iface->ipv6_router, ":")) { + if (!iface_fill_router_autocfg(&iov[net_config->count], + iface)) { + net_config->count++; + count++; + } + /* User provided Router Address */ + if (!iface_fill_net_ipv6_addr(&iov[net_config->count], + iface, + ISCSI_NET_PARAM_IPV6_ROUTER)) { + net_config->count++; + count++; + } + } + + /* + * If IPv6 configuration in iface file is valid, + * fill state and other parameters + */ + if (count) { + if (!iface_fill_net_state(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV6)) { + net_config->count++; + count++; + } + if (!iface_fill_vlan_state(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV6)) { + net_config->count++; + count++; + } + if (strcmp(iface->vlan_state, "disable") && + iface->vlan_id) { + if (!iface_fill_vlan_id(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV6)) { + net_config->count++; + count++; + } + } + if (iface->mtu) { + if (!iface_fill_mtu(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV6)) { + net_config->count++; + count++; + } + } + if (iface->port) { + if (!iface_fill_port(&iov[net_config->count], + iface, + ISCSI_IFACE_TYPE_IPV6)) { + net_config->count++; + count++; + } + } + } + } + return 0; +} + +/** + * iface_build_net_config - Setup neconfig parameter buffers + * @iface: iface to setup + * @iface_all: Flag for number of ifaces to traverse (1 for all) + * @iovs: iovec buffer for netconfig parameters + * + * Returns total number of netconfig parameter buffers used. + */ +int iface_build_net_config(struct iface_rec *iface, int iface_all, + struct iovec *iovs) +{ + int num_found = 0, rc; + struct iface_net_config net_config; + + log_debug(8, "In iface_build_net_config\n"); + + net_config.primary = iface; + net_config.iovs = iovs; + net_config.count = 0; + + if (iface_all) + rc = iface_for_each_iface(&net_config, 0, &num_found, + __iface_build_net_config); + else + rc = __iface_build_net_config(&net_config, iface); + + log_debug(8, "iface_build_net_config: rc = %d, count = %d\n", + rc, net_config.count); + return net_config.count; +} diff --git a/usr/iface.h b/usr/iface.h index 9f6d47e..3ba2a4e 100644 --- a/usr/iface.h +++ b/usr/iface.h @@ -54,6 +54,10 @@ extern int iface_setup_from_boot_context(struct iface_rec *iface, struct boot_context *context); extern int iface_create_ifaces_from_boot_contexts(struct list_head *ifaces, struct list_head *targets); +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); #define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]" #define iface_str(_iface) \ diff --git a/usr/iscsi_ipc.h b/usr/iscsi_ipc.h index 93b4917..8df3cdc 100644 --- a/usr/iscsi_ipc.h +++ b/usr/iscsi_ipc.h @@ -129,6 +129,9 @@ struct iscsi_ipc { int (*recv_pdu_begin) (struct iscsi_conn *conn); int (*recv_pdu_end) (struct iscsi_conn *conn); + + int (*set_net_config) (uint64_t transport_handle, uint32_t host_no, + struct iovec *iovs, uint32_t param_count); }; #endif /* ISCSI_IPC_H */ diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c index 8761e3f..9f7a6f2 100644 --- a/usr/iscsi_sysfs.c +++ b/usr/iscsi_sysfs.c @@ -325,7 +325,7 @@ static int __get_host_no_from_hwaddress(void *data, struct host_info *info) { struct host_info *ret_info = data; - if (!strcmp(ret_info->iface.hwaddress, info->iface.hwaddress)) { + if (!strcasecmp(ret_info->iface.hwaddress, info->iface.hwaddress)) { ret_info->host_no = info->host_no; return 1; } diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c index 3b87c3d..efc9e16 100644 --- a/usr/iscsiadm.c +++ b/usr/iscsiadm.c @@ -50,6 +50,7 @@ #include "iscsid_req.h" #include "isns-proto.h" #include "iscsi_err.h" +#include "iscsi_ipc.h" static char program_name[] = "iscsiadm"; static char config_file[TARGET_NAME_MAXLEN]; @@ -71,7 +72,9 @@ enum iscsiadm_op { OP_DELETE = 0x2, OP_UPDATE = 0x4, OP_SHOW = 0x8, - OP_NONPERSISTENT = 0x10 + OP_NONPERSISTENT = 0x10, + OP_APPLY = 0x20, + OP_APPLY_ALL = 0x40 }; static struct option const long_options[] = @@ -116,9 +119,9 @@ iscsiadm -m discovery [ -hV ] [ -d debug_level ] [-P printlevel] [ -t type -p ip iiscsiadm -m node [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -L all,manual,automatic ] [ -U all,manual,automatic ] [ -S ] [ [ -T targetname -p ip:port -I ifaceN ] [ -l | -u | -R | -s] ] \ [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ -iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ +iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename | -H hostno|MAC ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ iscsiadm -m fw [ -l ]\n\ -iscsiadm -m host [ -P printlevel ] [ -H hostno ]\n\ +iscsiadm -m host [ -P printlevel ] [ -H hostno|MAC ]\n\ iscsiadm -k priority\n"); } exit(status); @@ -139,6 +142,10 @@ str_to_op(char *str) op = OP_SHOW; else if (!strcmp("nonpersistent", str)) op = OP_NONPERSISTENT; + else if (!strcmp("apply", str)) + op = OP_APPLY; + else if (!strcmp("applyall", str)) + op = OP_APPLY_ALL; else op = OP_NOOP; @@ -1195,10 +1202,97 @@ static void catch_sigint( int signo ) { exit(1); } +static int iface_apply_net_config(struct iface_rec *iface, int op) +{ + int rc = ISCSI_ERR; + uint32_t host_no; + int param_count; + int param_used; + int iface_all = 0; + int i; + struct iovec *iovs = NULL; + struct iovec *iov = NULL; + struct iscsi_transport *t = NULL; + int fd; + + log_debug(8, "Calling iscsid, to apply net config for" + "iface.name = %s\n", iface->name); + + if (op == OP_APPLY_ALL) + iface_all = 1; + + param_count = iface_get_param_count(iface, iface_all); + if (!param_count) { + log_error("Nothing to configure."); + return ISCSI_SUCCESS; + } + + /* + * TODO: create a nicer interface where the caller does not have + * know the packet/hdr details + */ + + /* +2 for event and nlmsghdr */ + param_count += 2; + iovs = calloc((param_count * sizeof(struct iovec)), + sizeof(char)); + if (!iovs) { + log_error("Out of Memory."); + return ISCSI_ERR_NOMEM; + } + + /* param_used gives actual number of iovecs used for netconfig */ + param_used = iface_build_net_config(iface, iface_all, iovs); + if (!param_used) { + log_error("Build netconfig failed."); + goto free_buf; + } + + t = iscsi_sysfs_get_transport_by_name(iface->transport_name); + if (!t) { + log_error("Can't find transport."); + goto free_buf; + } + + host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc); + if (host_no == -1) { + log_error("Can't find host_no."); + goto free_buf; + } + rc = ISCSI_ERR; + + fd = ipc->ctldev_open(); + if (fd < 0) { + log_error("Netlink open failed."); + goto free_buf; + } + + rc = ipc->set_net_config(t->handle, host_no, iovs, param_count); + if (rc < 0) + log_error("Set net_config failed. errno=%d", errno); + + ipc->ctldev_close(); + +free_buf: + /* start at 2, because 0 is for nlmsghdr and 1 for event */ + iov = iovs + 2; + for (i = 0; i < param_used; i++, iov++) { + if (iov->iov_base) + free(iov->iov_base); + } + + free(iovs); + if (rc) + return ISCSI_ERR; + return ISCSI_SUCCESS; +} + /* TODO: merge iter helpers and clean them up, so we can use them here */ static int exec_iface_op(int op, int do_show, int info_level, - struct iface_rec *iface, char *name, char *value) + struct iface_rec *iface, uint32_t host_no, + char *name, char *value) { + struct host_info hinfo; struct db_set_param set_param; struct node_rec *rec = NULL; int rc = 0; @@ -1321,6 +1415,55 @@ update_fail: log_error("Could not update iface %s: %s", iface->name, iscsi_err_to_str(rc)); break; + case OP_APPLY: + if (!iface) { + log_error("Apply requires iface."); + rc = ISCSI_ERR_INVAL; + break; + } + rc = iface_conf_read(iface); + if (rc) { + log_error("Could not read iface %s (%d).", + iface->name, rc); + break; + } + + rc = iface_apply_net_config(iface, op); + if (rc) { + log_error("Could not apply net configuration: %s", + iscsi_err_to_str(rc)); + break; + } + printf("%s applied.\n", iface->name); + break; + case OP_APPLY_ALL: + if (host_no == -1) { + log_error("Applyall requires a host number or MAC " + "passed in with the --host argument."); + rc = ISCSI_ERR_INVAL; + break; + } + + /* + * Need to get other iface info like transport. + */ + memset(&hinfo, 0, sizeof(struct host_info)); + hinfo.host_no = host_no; + if (iscsi_sysfs_get_hostinfo_by_host_no(&hinfo)) { + log_error("Could not match host%u to ifaces.", host_no); + rc = ISCSI_ERR_INVAL; + break; + } + rc = iface_apply_net_config(&hinfo.iface, op); + if (rc) { + log_error("Could not apply net configuration: %s", + iscsi_err_to_str(rc)); + break; + } + + printf("Applied settings to ifaces attached to host%u.\n", + host_no); + break; default: if (!iface || (iface && info_level > 0)) { if (op == OP_NOOP || op == OP_SHOW) @@ -1925,6 +2068,30 @@ done: return rc; } +static uint32_t parse_host_info(char *optarg, int *rc) +{ + int err = 0; + uint32_t host_no = -1; + + *rc = 0; + if (strstr(optarg, ":")) { + host_no = iscsi_sysfs_get_host_no_from_hwaddress(optarg, + &err); + if (err) { + log_error("Could not match MAC to host."); + *rc = ISCSI_ERR_INVAL; + } + } else { + host_no = strtoul(optarg, NULL, 10); + if (errno) { + log_error("Invalid host no %s. %s.", + optarg, strerror(errno)); + *rc = ISCSI_ERR_INVAL; + } + } + return host_no; +} + int main(int argc, char **argv) { @@ -1991,14 +2158,9 @@ main(int argc, char **argv) value = optarg; break; case 'H': - errno = 0; - host_no = strtoul(optarg, NULL, 10); - if (errno) { - log_error("invalid host no %s. %s.", - optarg, strerror(errno)); - rc = ISCSI_ERR_INVAL; + host_no = parse_host_info(optarg, &rc); + if (rc) goto free_ifaces; - } break; case 'r': sid = iscsi_sysfs_get_sid_from_path(optarg); @@ -2122,7 +2284,7 @@ main(int argc, char **argv) case MODE_IFACE: iface_setup_host_bindings(); - if ((rc = verify_mode_params(argc, argv, "IdnvmPo", 0))) { + if ((rc = verify_mode_params(argc, argv, "HIdnvmPo", 0))) { log_error("iface mode: option '-%c' is not " "allowed/supported", rc); rc = ISCSI_ERR_INVAL; @@ -2137,7 +2299,7 @@ main(int argc, char **argv) "interface. Using the first one " "%s.", iface->name); } - rc = exec_iface_op(op, do_show, info_level, iface, + rc = exec_iface_op(op, do_show, info_level, iface, host_no, name, value); break; case MODE_DISCOVERYDB: diff --git a/usr/netlink.c b/usr/netlink.c index 957fdb6..8fc61e1 100644 --- a/usr/netlink.c +++ b/usr/netlink.c @@ -161,7 +161,6 @@ kwritev(enum iscsi_uevent_e type, struct iovec *iovp, int count) int i, rc; struct nlmsghdr *nlh; struct msghdr msg; - struct iovec iov; int datalen = 0; log_debug(7, "in %s", __FUNCTION__); @@ -180,27 +179,25 @@ kwritev(enum iscsi_uevent_e type, struct iovec *iovp, int count) } nlh = nlm_sendbuf; - memset(nlh, 0, NLMSG_SPACE(datalen)); + memset(nlh, 0, NLMSG_SPACE(0)); - nlh->nlmsg_len = NLMSG_SPACE(datalen); + datalen = 0; + for (i = 1; i < count; i++) + datalen += iovp[i].iov_len; + + nlh->nlmsg_len = NLMSG_ALIGN(datalen); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; nlh->nlmsg_type = type; - datalen = 0; - for (i = 0; i < count; i++) { - memcpy(NLMSG_DATA(nlh) + datalen, iovp[i].iov_base, - iovp[i].iov_len); - datalen += iovp[i].iov_len; - } - iov.iov_base = (void*)nlh; - iov.iov_len = nlh->nlmsg_len; + iovp[0].iov_base = (void *)nlh; + iovp[0].iov_len = sizeof(*nlh); memset(&msg, 0, sizeof(msg)); msg.msg_name= (void*)&dest_addr; msg.msg_namelen = sizeof(dest_addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + msg.msg_iov = iovp; + msg.msg_iovlen = count; do { /* @@ -261,19 +258,15 @@ kwritev(enum iscsi_uevent_e type, struct iovec *iovp, int count) * cleanup. (Dima) */ static int -__kipc_call(void *iov_base, int iov_len) +__kipc_call(struct iovec *iovp, int count) { int rc, iferr; - struct iovec iov; - struct iscsi_uevent *ev = iov_base; + struct iscsi_uevent *ev = iovp[1].iov_base; enum iscsi_uevent_e type = ev->type; log_debug(7, "in %s", __FUNCTION__); - iov.iov_base = iov_base; - iov.iov_len = iov_len; - - rc = kwritev(type, &iov, 1); + rc = kwritev(type, iovp, count); do { if ((rc = nlpayload_read(ctrl_fd, (void*)ev, @@ -333,6 +326,7 @@ ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr) { int rc, addrlen; struct iscsi_uevent *ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -354,7 +348,9 @@ ksendtargets(uint64_t transport_handle, uint32_t host_no, struct sockaddr *addr) } memcpy(setparam_buf + sizeof(*ev), addr, addrlen); - rc = __kipc_call(ev, sizeof(*ev) + addrlen); + iov[1].iov_base = ev; + iov[1].iov_len = sizeof(*ev) + addrlen; + rc = __kipc_call(iov, 2); if (rc < 0) { log_error("sendtargets failed rc%d\n", rc); return rc; @@ -369,6 +365,7 @@ kcreate_session(uint64_t transport_handle, uint64_t ep_handle, { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -389,9 +386,11 @@ kcreate_session(uint64_t transport_handle, uint64_t ep_handle, ev.u.c_bound_session.ep_handle = ep_handle; } - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } *hostno = ev.r.c_session_ret.host_no; *out_sid = ev.r.c_session_ret.sid; @@ -404,6 +403,7 @@ kdestroy_session(uint64_t transport_handle, uint32_t sid) { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -413,9 +413,11 @@ kdestroy_session(uint64_t transport_handle, uint32_t sid) ev.transport_handle = transport_handle; ev.u.d_session.sid = sid; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } return 0; } @@ -425,6 +427,7 @@ kunbind_session(uint64_t transport_handle, uint32_t sid) { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -434,9 +437,11 @@ kunbind_session(uint64_t transport_handle, uint32_t sid) ev.transport_handle = transport_handle; ev.u.d_session.sid = sid; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } return 0; } @@ -447,6 +452,7 @@ kcreate_conn(uint64_t transport_handle, uint32_t sid, { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -457,7 +463,10 @@ kcreate_conn(uint64_t transport_handle, uint32_t sid, ev.u.c_conn.cid = cid; ev.u.c_conn.sid = sid; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) { log_debug(7, "returned %d", rc); return rc; } @@ -474,6 +483,7 @@ kdestroy_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid) { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -484,9 +494,11 @@ kdestroy_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid) ev.u.d_conn.sid = sid; ev.u.d_conn.cid = cid; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } return 0; } @@ -497,6 +509,7 @@ kbind_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -509,9 +522,11 @@ kbind_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, ev.u.b_conn.transport_eph = transport_eph; ev.u.b_conn.is_leading = is_leading; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } *retcode = ev.r.retcode; @@ -559,7 +574,7 @@ ksend_pdu_end(uint64_t transport_handle, uint32_t sid, uint32_t cid, { int rc; struct iscsi_uevent *ev; - struct iovec iov; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -573,10 +588,11 @@ ksend_pdu_end(uint64_t transport_handle, uint32_t sid, uint32_t cid, exit(-EIO); } - iov.iov_base = xmitbuf; - iov.iov_len = xmitlen; + iov[1].iov_base = xmitbuf; + iov[1].iov_len = xmitlen; - if ((rc = __kipc_call(xmitbuf, xmitlen)) < 0) + rc = __kipc_call(iov, 2); + if (rc < 0) goto err; if (ev->r.retcode) { *retcode = ev->r.retcode; @@ -606,6 +622,7 @@ kset_host_param(uint64_t transport_handle, uint32_t host_no, struct iscsi_uevent *ev; char *param_str; int rc, len; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -632,9 +649,11 @@ kset_host_param(uint64_t transport_handle, uint32_t host_no, } ev->u.set_host_param.len = len = strlen(param_str) + 1; - if ((rc = __kipc_call(ev, sizeof(*ev) + len)) < 0) { + iov[1].iov_base = ev; + iov[1].iov_len = sizeof(*ev) + len; + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } return 0; } @@ -646,6 +665,7 @@ kset_param(uint64_t transport_handle, uint32_t sid, uint32_t cid, struct iscsi_uevent *ev; char *param_str; int rc, len; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -673,9 +693,11 @@ kset_param(uint64_t transport_handle, uint32_t sid, uint32_t cid, } ev->u.set_param.len = len = strlen(param_str) + 1; - if ((rc = __kipc_call(ev, sizeof(*ev) + len)) < 0) { + iov[1].iov_base = ev; + iov[1].iov_len = sizeof(*ev) + len; + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } return 0; } @@ -685,6 +707,7 @@ kstop_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, int flag) { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -696,9 +719,11 @@ kstop_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, int flag) ev.u.stop_conn.cid = cid; ev.u.stop_conn.flag = flag; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } return 0; } @@ -709,6 +734,7 @@ kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -719,9 +745,11 @@ kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, ev.u.start_conn.sid = sid; ev.u.start_conn.cid = cid; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } *retcode = ev.r.retcode; return 0; @@ -786,6 +814,7 @@ ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking) int rc, addrlen; struct iscsi_uevent *ev; struct sockaddr *dst_addr = (struct sockaddr *)&conn->saddr; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -813,7 +842,10 @@ ktransport_ep_connect(iscsi_conn_t *conn, int non_blocking) } memcpy(setparam_buf + sizeof(*ev), dst_addr, addrlen); - if ((rc = __kipc_call(ev, sizeof(*ev) + addrlen)) < 0) + iov[1].iov_base = ev; + iov[1].iov_len = sizeof(*ev) + addrlen; + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; if (!ev->r.ep_connect_ret.handle) @@ -831,6 +863,7 @@ ktransport_ep_poll(iscsi_conn_t *conn, int timeout_ms) { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -841,7 +874,10 @@ ktransport_ep_poll(iscsi_conn_t *conn, int timeout_ms) ev.u.ep_poll.ep_handle = conn->transport_ep_handle; ev.u.ep_poll.timeout_ms = timeout_ms; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; return ev.r.retcode; @@ -852,6 +888,7 @@ ktransport_ep_disconnect(iscsi_conn_t *conn) { int rc; struct iscsi_uevent ev; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -864,7 +901,10 @@ ktransport_ep_disconnect(iscsi_conn_t *conn) ev.transport_handle = conn->session->t->handle; ev.u.ep_disconnect.ep_handle = conn->transport_ep_handle; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) { log_error("connnection %d:%d transport disconnect failed for " "ep %" PRIu64 " with error %d.", conn->session->id, conn->id, conn->transport_ep_handle, rc); @@ -881,6 +921,7 @@ kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid, struct iscsi_uevent ev; char nlm_ev[NLMSG_SPACE(sizeof(struct iscsi_uevent))]; struct nlmsghdr *nlh; + struct iovec iov[2]; log_debug(7, "in %s", __FUNCTION__); @@ -891,9 +932,11 @@ kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid, ev.u.get_stats.sid = sid; ev.u.get_stats.cid = cid; - if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { + iov[1].iov_base = &ev; + iov[1].iov_len = sizeof(ev); + rc = __kipc_call(iov, 2); + if (rc < 0) return rc; - } if ((rc = nl_read(ctrl_fd, nlm_ev, NLMSG_SPACE(sizeof(struct iscsi_uevent)), MSG_PEEK)) < 0) { @@ -919,6 +962,32 @@ kget_stats(uint64_t transport_handle, uint32_t sid, uint32_t cid, return 0; } +static int +kset_net_config(uint64_t transport_handle, uint32_t host_no, + struct iovec *iovs, uint32_t param_count) +{ + struct iscsi_uevent ev; + int rc, ev_len; + struct iovec *iov = iovs + 1; + + log_debug(8, "in %s", __FUNCTION__); + + ev_len = sizeof(ev); + ev.type = ISCSI_UEVENT_SET_IFACE_PARAMS; + ev.transport_handle = transport_handle; + ev.u.set_iface_params.host_no = host_no; + /* first two iovs for nlmsg hdr and ev */ + ev.u.set_iface_params.count = param_count - 2; + + iov->iov_base = &ev; + iov->iov_len = ev_len; + rc = __kipc_call(iovs, param_count); + if (rc < 0) + return rc; + + return 0; +} + static void drop_data(struct nlmsghdr *nlh) { int ev_size; @@ -1163,6 +1232,7 @@ struct iscsi_ipc nl_ipc = { .read = kread, .recv_pdu_begin = krecv_pdu_begin, .recv_pdu_end = krecv_pdu_end, + .set_net_config = kset_net_config, }; struct iscsi_ipc *ipc = &nl_ipc; diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c index 9010339..f5b361e 100644 --- a/utils/fwparam_ibft/fw_entry.c +++ b/utils/fwparam_ibft/fw_entry.c @@ -200,7 +200,7 @@ static void dump_network(struct boot_context *context) if (strlen(context->secondary_dns)) printf("%s = %s\n", IFACE_SEC_DNS, context->secondary_dns); if (strlen(context->vlan)) - printf("%s = %s\n", IFACE_VLAN, context->vlan); + printf("%s = %s\n", IFACE_VLAN_ID, context->vlan); if (strlen(context->iface)) printf("%s = %s\n", IFACE_NETNAME, context->iface); } -- 2.11.4.GIT