summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README48
-rw-r--r--doc/iscsiadm.820
-rw-r--r--etc/iface.example135
-rw-r--r--include/iscsi_if.h83
-rw-r--r--usr/config.h17
-rw-r--r--usr/idbm.c57
-rw-r--r--usr/idbm.h2
-rw-r--r--usr/idbm_fields.h13
-rw-r--r--usr/iface.c822
-rw-r--r--usr/iface.h4
-rw-r--r--usr/iscsi_ipc.h3
-rw-r--r--usr/iscsi_sysfs.c2
-rw-r--r--usr/iscsiadm.c188
-rw-r--r--usr/netlink.c168
-rw-r--r--utils/fwparam_ibft/fw_entry.c2
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,<empty>,<empty>,<empty>,<empty>
iser iser,<empty>,<empty>,<empty>,<empty>
cxgb3i.00:07:43:05:97:07 cxgb3i,00:07:43:05:97:07,<empty>,<empty>,<empty>
+qla4xxx.00:0e:1e:04:8b:2e qla4xxx,00:0e:1e:04:8b:2e,<empty>,<empty>,<empty>
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 = <empty>
+# 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 = <empty>
+# 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 = <empty>
+# 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 = <empty>
+# iface.linklocal_autocfg = <empty>
+# iface.router_autocfg = <empty>
+# 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 = <empty>
+# 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 <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <arpa/inet.h>
#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);
}