# Howto iSCSI

<http://en.wikipedia.org/wiki/ISCSI>

Vocabulaire : l'initiator est le client iSCSI, le target est le serveur iSCSI.

## Installation d'un initiator

Sous Debian, l'utilitaire pour avoir un initiator iSCSI est fourni avec le paquet _open-iscsi_.

~~~
# apt install open-iscsi
~~~

S'assurer que _iscsid_ est bien démarré :

~~~
# systemctl status open-iscsi
~~~

A l'installation, l'IQN de l'initiator est généré, on peut le trouver dans */etc/iscsi/initiatorname.iscsi*

~~~
# cat /etc/iscsi/initiatorname.iscsi
## DO NOT EDIT OR REMOVE THIS FILE!
## If you remove this file, the iSCSI daemon will not start.
## If you change the InitiatorName, existing access control lists
## may reject this initiator.  The InitiatorName must be unique
## for each iSCSI initiator.  Do NOT duplicate iSCSI InitiatorNames.
InitiatorName=iqn.1993-08.org.debian:01:bf80c8fe52
~~~

Scanner les devices disponibles :

~~~
# iscsiadm -m discovery -t sendtargets -p IP_ADDRESS
~~~

### Configuration simple

Une configuration simple est lorsque vous avez une liaison iSCSI via une seule interface Ethernet.

Exemple pour attacher le device iSCSI :

~~~
# iscsiadm --mode node --targetname iqn.2002-10.com.infortrend:raid.sn8128457.001 --portal IP_ADDRESS:3260 --login
Logging in to [iface: default, target: iqn.2002-10.com.infortrend:raid.sn8128457.001, portal: IP_ADDRESS,3260]
Login to [iface: default, target: iqn.2002-10.com.infortrend:raid.sn8128457.001, portal: IP_ADDRESS,3260]: successful
~~~

Un dmesg nous confirme que le device iSCSI est attaché :

~~~
[589633.268035] Loading iSCSI transport class v2.0-870.
[589634.206569] iscsi: registered transport (tcp)
[589634.533062] iscsi: registered transport (iser)
[590317.751042] scsi2 : iSCSI Initiator over TCP/IP
[590318.406292] scsi 2:0:0:0: Direct-Access     IFT      DS S12E-G2140-4  386C PQ: 0 ANSI: 5
[590318.500371] scsi 2:0:0:0: Attached scsi generic sg1 type 0
[590318.502537] scsi 2:0:0:1: Enclosure         IFT      DS S12E-G2140-4  386C PQ: 0 ANSI: 4
[590318.502613] scsi 2:0:0:1: Attached scsi generic sg2 type 13
[590318.568943] sd 2:0:0:0: [sda] 19528073216 512-byte logical blocks: (9.99 TB/9.09 TiB)
[590318.598211] sd 2:0:0:0: [sda] Write Protect is off
[590318.598214] sd 2:0:0:0: [sda] Mode Sense: 83 00 00 08
[590318.599120] sd 2:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[590318.664632]  sda: unknown partition table
[590318.703094] sd 2:0:0:0: [sda] Attached SCSI disk
[590318.725349] ses 2:0:0:1: Attached Enclosure device
~~~

### Gestion des volumes

Pour lister les sessions iSCSI ouvertes :

~~~
# iscsiadm -m session
~~~

Pour se déconnecter proprement d'un target (après avoir démonté les disques) :

~~~
# iscsiadm -m node -u
~~~

Pour déconnecter un seul LUN d'un target :

~~~
# iscsiadm -m node -T [iqn du LUN] --logout
~~~

## Montage au démarrage

Une fois la configuration testée et validée, il est souhaitable que les volumes iSCSI soient montés automatiquement au démarrage du serveur.

### Connexion aux LUNs

Lorsqu'on lance la détection des volumes d'un target, ou que l'on se connecte à ce dernier, la commande _iscsiadm_ créée des fichiers de configuration dans /etc/iscsi/nodes et /etc/iscsi/send_targets.
Ces fichiers sont relativement simples à comprendre, mais une option nous intéresse plus particulièrement :

Dans le répertoire /etc/iscsi/nodes sont stockés les nodes auxquels nous nous sommes déjà connecté sous la forme :

~~~
[iqn]/[ip],[port],1/default
~~~

Par exemple, pour un SAN MD3600i en multipath nous avons :

~~~
# ls -l /etc/iscsi/nodes/iqn.1984-05.com.dell\:powervault.md3600i.36782bcb00050034200000xxxxxxxxxx/
drw------- 2 root root 4096 Oct 26  2011 192.0.2.101,3260,1
drw------- 2 root root 4096 Oct 26  2011 192.0.2.102,3260,1
~~~

Pour se connecter automatiquement aux LUNs au démarrage du serveur, il faut modifier la directive "node.startup" en la passant de "manual" à "automatic" :

~~~
# cat /etc/iscsi/nodes/iqn.1984-05.com.dell\:powervault.md3600i.36782bcb00050034200000xxxxxxxxxx/192.0.2.101\,3260\,1
node.name = iqn.1984-05.com.dell:powervault.md3600i.36782bcb00050034200000xxxxxxxxxx
node.tpgt = 1
node.startup = automatic
iface.iscsi_ifacename = default
iface.transport_name = tcp
node.discovery_address = 192.0.2.101
node.discovery_port = 3260
node.discovery_type = send_targets
[...]
~~~

### /etc/fstab

Lorsque les partition d'un device iSCSI sont ajoutées au fichier fstab, ne pas oublier l'option "netdev": elle permet non seulement d'attendre que le réseau soit actif avant de chercher à monter la partition (pour ne pas bloquer le démarrage du serveur, ce serait dommage...) mais aussi de démonter la/les partitions à l'extinction de la machine avant de couper le réseau afin d'éviter toute corruption du filesystem (encore une fois, ce serait dommage).

~~~
/dev/mapper/data /home                                    ext3    _netdev,defaults,noexec,nosuid,nodev  0       0
~~~

### Configuration avec deux interfaces et deux liaisons indépendantes vers un target

Vous configurez vos 2 interfaces sur une plage réseau différente. Vous pouvez ainsi
scanner le target sur 2 IPs complètement distinctes :

~~~
# iscsiadm -m discovery -t sendtargets -p IP_ADDRESS1
# iscsiadm -m discovery -t sendtargets -p IP_ADDRESS2
~~~

Puis attacher les devices deux fois indépendamment :

~~~
# iscsiadm --mode node --targetname qn.2002-10.com.infortrend:raid.sn8128457.001 --portal IP_ADDRESS1:3260 --login
# iscsiadm --mode node --targetname qn.2002-10.com.infortrend:raid.sn8128457.001 --portal IP_ADDRESS2:3260 --login
~~~

Vous pouvez ainsi accéder au target via plusieurs devices ! Pour gérer du multipath, voir ci-dessous.

### Configuration avec deux interfaces et liaison unique vers un target

Si vous êtes connectés avec d'autres initiator iSCSI (c'est souvent le cas), vous
serez sûrement connectés sur un switch dédié au iSCSI. Le target qui a en général
plusieurs interfaces Ethernet aura probablement des adresses IP sur la même plage.
Vous allez donc configurer vos deux interfaces avec des IPs sur la même plage :

~~~
# ifconfig eth2 192.0.2.200/24
# ifconfig eth3 192.0.2.201/24
~~~

Il faut alors créer des interfaces iSCSI pour chaque carte réseau :

~~~
# iscsiadm --mode iface --op=new --interface iscsi-0
New interface iscsi-0 added
# iscsiadm --mode iface --op=new --interface iscsi-1
New interface iscsi-1 added
# iscsiadm --mode iface --op=update --interface iscsi-0 --name=iface.net_ifacename --value=eth2
iscsi-0 updated.
# iscsiadm --mode iface --op=update --interface iscsi-1 --name=iface.net_ifacename --value=eth3
iscsi-1 updated.
# iscsiadm --mode iface
default tcp,<empty>,<empty>,<empty>,<empty>
iser iser,<empty>,<empty>,<empty>,<empty>
iscsi-0 tcp,<empty>,<empty>,eth2,<empty>
iscsi-1 tcp,<empty>,<empty>,eth3,<empty>
# iscsiadm --mode iface --interface iscsi-0
# BEGIN RECORD 2.0-871
iface.iscsi_ifacename = iscsi-0
iface.net_ifacename = eth2
iface.ipaddress = <empty>
iface.hwaddress = <empty>
iface.transport_name = tcp
iface.initiatorname = <empty>
# END RECORD
# iscsiadm --mode iface --interface iscsi-1
# BEGIN RECORD 2.0-871
iface.iscsi_ifacename = iscsi-1
iface.net_ifacename = eth3
iface.ipaddress = <empty>
iface.hwaddress = <empty>
iface.transport_name = tcp
iface.initiatorname = <empty>
# END RECORD
~~~

Puis attacher les devices deux fois via chaque interface iSCSI :

~~~
# iscsiadm --mode node --targetname qn.2002-10.com.infortrend:raid.sn8128457.001 --portal IP_ADDRESS:3260 -I iscsi-0--login
# iscsiadm --mode node --targetname qn.2002-10.com.infortrend:raid.sn8128457.001 --portal IP_ADDRESS:3260 -I iscsi-1 --login
~~~

On obtient donc plusieurs périphériques identiques. Pour gérer du multipath, voir ci-dessous.

## Multipath

Lorsque l'on a plusieurs paths vers un device (voir ci-dessus), l'idée est de
profiter de cela pour avoir une tolérance de panne et une agrégation des débits.

### Utilisation du multipath

~~~
# apt install multipath-tools
modprobe dm_multipath
~~~

On peut voir les différents chemins pour accèder à un même périphérique :

~~~
# multipath -ll
3600d0231000b3f9e55030d29266ffe95 dm-2 IFT,DS S12E-G2140-4
size=1.8T features='0' hwhandler='0' wp=rw
|-+- policy='round-robin 0' prio=1 status=active
| `- 7:0:0:0 sdd 8:48  active ready running
`-+- policy='round-robin 0' prio=1 status=enabled
  `- 8:0:0:0 sdg 8:96  active ready running
3600d0231000b3f9e6075561c390db5ce dm-4 IFT,DS S12E-G2140-4
size=836G features='0' hwhandler='0' wp=rw
|-+- policy='round-robin 0' prio=1 status=active
| `- 7:0:0:2 sdf 8:80  active ready running
`-+- policy='round-robin 0' prio=1 status=enabled
  `- 8:0:0:2 sdi 8:128 active ready running
3600d0231000b3f9e68e8e32f513c36b5 dm-3 IFT,DS S12E-G2140-4
size=3.6T features='0' hwhandler='0' wp=rw
|-+- policy='round-robin 0' prio=1 status=active
| `- 7:0:0:1 sde 8:64  active ready running
`-+- policy='round-robin 0' prio=1 status=enabled
  `- 8:0:0:1 sdh 8:112 active ready running
~~~

On doit ensuite configurer _multipathd_ via
un fichier */etc/multipath.conf*. Voici un exemple (utilisé
avec un SAN LENOVO S2200) :

~~~
defaults {
    polling_interval 5
    user_friendly_names yes
    path_selector "round-robin 0"
}
blacklist {
    wwid ".*"
}
blacklist_exceptions {
    wwid "3600c0ff00026xxxxxxxxxxxxxxxxxxxx"
}
multipaths {
    multipath {
        wwid 3600c0ff00026xxxxxxxxxxxxxxxxxxxx
        alias data
    }
}
devices {
    device {
        vendor "Lenovo"
        product "S2200"
        path_grouping_policy multibus
        failback immediate
        no_path_retry fail
        features "1 queue_if_no_path"
    }
}
~~~

* Pour trouver le `wwid` du volume on peux faire la commande suivante, exemple avec le volume `/dev/sdd/`

~~~
# /lib/udev/scsi_id -g /dev/sdd
3600c0ff00026edf2aff87c5801000000
~~~


On relance le daemon :

~~~
# /etc/init.d/multipath-tools restart
~~~

Et on vérifie :

~~~
# multipath -ll
data (3600c0ff00026xxxxxxxxxxxxxxxxxxxx) dm-0 Lenovo,S2200
size=8.6T features='0' hwhandler='0' wp=rw
`-+- policy='round-robin 0' prio=1 status=active
  |- 5:0:0:0 sdb 8:16  active ready running
  |- 6:0:0:0 sdd 8:48  active ready running
  |- 7:0:0:0 sdf 8:80  active ready running
  `- 8:0:0:0 sdh 8:112 active ready running
~~~

La politique multibus semble la plus intéressante car elle permet de gérer aussi bien le fail-over (en cas de perte d'un lien) que l'agrégation de débit.
L'option "failback immediate" indique de basculer sur le ou les lien(s) restant(s) dès qu'une erreur apparait, mais la bascule met 130s dans la configuration précédente, car c'est la couche SCSI qui remonte l'erreur à multipathd et le timeout par défaut d'open-iscsi est de 120 secondes. On peut régler la valeur de ce timeout dans le fichier /etc/iscsi/iscsid.conf pour les nouveaux targets, mais il ne faut pas oublier que les targets déjà configurés (même après déconnexion/reconnexion) conservent leurs paramètres dans /etc/iscsi/send_targets/[...], on modifiera donc également ces fichiers.

Exemple avec notre baie Dell :

~~~
# cat /etc/iscsi/nodes/iqn.2002-09.com.lenovo\:01.array.00xxxxxxxx/192.0.2.101\,3260\,1/default
# BEGIN RECORD 2.0-873
node.name = iqn.2002-09.com.lenovo:01.array.00xxxxxxxx
node.tpgt = 1
node.startup = automatic
node.leading_login = No
iface.iscsi_ifacename = default
iface.transport_name = tcp
iface.vlan_id = 0
iface.vlan_priority = 0
iface.iface_num = 0
iface.mtu = 0
iface.port = 0
node.discovery_address = 192.0.2.101
node.discovery_port = 3260
node.discovery_type = send_targets
node.session.initial_cmdsn = 0
node.session.initial_login_retry_max = 8
node.session.xmit_thread_priority = -20
node.session.cmds_max = 128
node.session.queue_depth = 32
node.session.nr_sessions = 1
node.session.auth.authmethod = None
node.session.timeo.replacement_timeout = 10
# END RECORD

~~~


### Pour ne plus utiliser multipathd

Commencer par démonter les partitions :

~~~
# umount /dev/mapper/data
~~~

Stopper les utilitaires multipath :

~~~
# /etc/init.d/multipath-tools stop
~~~

Et purger la liste des différents paths pour la/les ressource(s) :

~~~
# multipath -F
~~~

On peut vérifier :

~~~
# multipath -ll
~~~

Éventuellement, on peut retirer les modules à présent inutilisés :

~~~
# rmmod dm_round_robin dm_multipath
~~~
