|
|
- #!/bin/sh
- #
- # iscsi_offload
- #
- # Configure iSCSI offload engines for use with open-iscsi
- # Usage:
- # iscsi_offload [-d | -f | -i <ipaddr> | -t ] <nic>
- #
- # Copyright (c) 2011 Hannes Reinecke, SUSE Labs
- # This script is licensed under the GPL.
- #
- # The script creates an open-iscsi interface definition
- # in the style <nic>-<module>, where <nic> matches the
- # network interface passed on the commandline.
- # If '-t' (test mode) is passed as an option, the script
- # will not create nor modify any setting but just print
- # the currently active ones.
- #
- # Currently the script works with Broadcom (bnx2i) and
- # Chelsio T3 (cxgbi) iSCSI offload engines.
- # Should work with Chelsio T4, but has not been tested.
- # ServerEngines (be2iscsi) and QLogic (qla4xxx) can only
- # be configured via BIOS, open-iscsi support is still in
- # development.
- #
-
- #
- # Return codes:
- # 0: Success
- # 1: Invalid command line parameter
- # 2: iSCSI offloading not supported
- # 3: Error during module loading
- # 4: Cannot configure interface via iscsiadm, use BIOS setup
- # 5: internal error running iscsiadm
- #
- # Output:
- # <mac> [none|dhcp|ip <ipaddr>|ibft]
- # where
- # <mac>: MAC Address of the iSCSI offload engine
- # none: No IP configuration set for the iSCSI offload engine
- # dhcp: iSCSI offload engine configured for DHCP
- # ip: iSCSI offload engine configured with static IP address <ipaddr>
- # ibft: iSCSI offload engine configured from iBFT values
- #
-
- #
- # Figure out the MAC address of the iSCSI offload engine
- # corresponding to a NIC from a given PCI device.
- # bnx2 is using one PCI device per port for both network and iSCSI offloading
- # cxgb3 is using one PCI device for everything.
- #
- iscsi_macaddress_from_pcidevice()
- {
- local path=$1
- local if=$2
- local h
- local host
-
- for h in $path/host* ; do
- if [ -d "$h" ] ; then
- host=${h##*/}
- read netdev < /sys/class/iscsi_host/$host/netdev
- if [ "$netdev" = "$IFNAME" ] ; then
- read mac < /sys/class/iscsi_host/$host/hwaddress
- if [ "$mac" != "00:00:00:00:00:00" ] ; then
- echo "$mac"
- fi
- break;
- fi
- fi
- done
- }
-
- #
- # Figure out the MAC address of the iSCSI offload engine
- # corresponding to a NIC from a given PCI function.
- # It is assumed that the MAC address of the iSCSI offload
- # engine is equal of the MAC address of the NIC plus one.
- # Suitable for be2iscsi and qla4xxx
- #
- iscsi_macaddress_from_pcifn()
- {
- local path=$1
- local if=$2
- local h
- local host
- local ifmac
-
- ifmac=$(ip addr show dev $if | sed -n 's/ *link\/ether \(.*\) brd.*/\1/p')
- m5=$(( 0x${ifmac##*:} ))
- m5=$(( $m5 + 1 ))
- ifmac=$(printf "%s:%02x" ${ifmac%:*} $m5)
- for host in /sys/class/iscsi_host/host* ; do
- if [ -L "$host" ] ; then
- read mac < $host/hwaddress
- if [ "$mac" = "$ifmac" ] ; then
- echo "$mac"
- break;
- fi
- fi
- done
- }
-
- update_iface_setting() {
- local iface="$1"
- local name="$2"
- local value="$3"
-
- iface_value=$(iscsiadm -m iface -I $iface | sed -n "s/$name = \(.*\)/\1/p")
- if [ "$iface_value" = "<empty>" ] ; then
- iface_value=
- fi
- if [ "$iface_value" != "$value" ] ; then
- if ! iscsiadm -m iface -I $iface -o update -n "$name" -v "$value" ; then
- return 1
- fi
- fi
- return 0
- }
-
- while getopts di:t options ; do
- case $options in
- d ) mode=dhcp;;
- i ) mode=static
- optaddr=$OPTARG
- ;;
- f ) mode=firmware;;
- t ) dry_run=1;;
- ?) printf "Usage: %s [-d|-t|-i ipaddr|-f] ifname\n" $0
- exit 1;;
- esac
- done
- shift $(($OPTIND - 1))
-
- IFNAME=$1
- ibft_mode="none"
-
- if [ -z "$IFNAME" ] ; then
- echo "No interface specified"
- exit 1
- fi
-
- if [ "$dry_run" ] ; then
- if [ "$mode" = "dhcp" ] ; then
- echo "'-t' specified, ignoring '-d'"
- mode=
- elif [ "$mode" = "static" ] ; then
- echo "'-t' specified, ignoring '-s'"
- mode=
- fi
- fi
-
- if [ ! -L /sys/class/net/$IFNAME ] ; then
- echo "Interface $IFNAME not found"
- exit 1
- fi
-
- if [ "$optaddr" ] && ! ip route get $optaddr ; then
- echo "Invalid IP address $optaddr"
- exit 1
- fi
- if [ "$dry_run" ] ; then
- mode=
- fi
-
-
- ifpath=$(cd -P /sys/class/net/$IFNAME; echo $PWD)
- pcipath=$(cd -P $ifpath/device; echo $PWD)
-
- if [ -d $pcipath ] ; then
- drvlink=$(readlink $pcipath/driver)
- driver=${drvlink##*/}
- fi
-
- if [ -z "$driver" ] ; then
- echo "No driver found for interface $IFNAME"
- exit 1
- fi
-
- case "$driver" in
- bnx2*)
- mod=bnx2i
- ;;
- cxgb*)
- mod=cxgb3i
- ;;
- be2*)
- mod=be2iscsi
- ;;
- qla*)
- mod=qla4xxx
- ;;
- esac
-
- if [ -z "$mod" ] ; then
- echo "iSCSI offloading not supported on interface $IFNAME"
- exit 2
- fi
-
- # Check if the required modules are already loaded
- loaded=$(sed -n "/^$mod/p" /proc/modules)
- if [ -z "$loaded" ] ; then
- modprobe $mod
- fi
-
- loaded=$(sed -n "/^$mod/p" /proc/modules)
- if [ -z "$loaded" ] ; then
- echo "Loading of $mod.ko failed, please check dmesg"
- exit 3
- fi
-
- # Get the correct MAC address for the various devices
- if [ "$mod" = "bnx2i" ] ; then
- mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME)
- elif [ "$mod" = "cxgb3i" ] ; then
- mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME)
- elif [ "$mod" = "be2iscsi" ] ; then
- mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME)
- elif [ "$mod" = "qla4xxx" ] ; then
- mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME)
- fi
-
- if [ -z "$mac" ] ; then
- echo "iSCSI offloading not supported on interface $IFNAME"
- exit 2
- fi
-
- gen_iface="$mod.$mac"
- ioe_iface="${IFNAME}-${mod}"
-
- # Get existing settings
- if iscsiadm -m iface -I $ioe_iface > /dev/null 2>&1 ; then
- ioe_mac=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.hwaddress = \(.*\)/\1/p")
- ioe_mod=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.transport_name = \(.*\)/\1/p")
- ipaddr=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p")
- if [ "$ipaddr" == "<empty>" ] ; then
- ipaddr=
- fi
- elif [ "$mod" = "be2iscsi" ] ; then
- ioe_mac=$mac
- ioe_mod=$mod
- else
- # Create new interface
- iscsiadm -m iface -I $ioe_iface --op=new 2> /dev/null
- ioe_mac=
- ioe_mod=
- ipaddr=
- fi
-
- if [ -z "$dry_run" ] ; then
- if [ "$ioe_mac" != "$mac" ] ; then
- if [ -n "$ioe_mac" ] ; then
- echo "Warning: Updating MAC address on iface $ioe_iface"
- fi
- update_iface_setting $ioe_iface iface.hwaddress "$mac"
- fi
-
- if [ "$ioe_mod" != "$mod" ] ; then
- if [ -n "$ioe_mod" ] ; then
- echo "Warning: Update transport on iface $ioe_iface"
- fi
- update_iface_setting $ioe_iface iface.transport_name "$mod"
- fi
- elif [ -z "$ipaddr" ] ; then
- ipaddr=$(iscsiadm -m iface -I $gen_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p")
- if [ "$ipaddr" = "<empty>" ] ; then
- ipaddr=
- fi
- elif [ "$ioe_mod" != "$mod" ] ; then
- echo "Warning: Transport mismatch on iface $ioe_iface: $ioe_mod should be $mod"
- fi
-
- # Check iBFT setting
- for d in /sys/firmware/* ; do
- [ -d $d ] || continue
- [ -d $d/ethernet0 ] || continue
- iboot_dir=$d
- done
- if [ -n "$iboot_dir" ] && [ -d "$iboot_dir" ] ; then
- for if in ${iboot_dir}/ethernet* ; do
- read ibft_mac < $if/mac
- [ "$ibft_mac" = "$mac" ] || continue
- ibft_origin=0
- [ -f ${if}/origin ] && read ibft_origin < $if/origin
- if [ "$ibft_origin" -eq 1 ] ; then
- ibft_mode="static"
- elif [ "$ibft_origin" -eq 3 ] ; then
- ibft_mode="dhcp"
- fi
- [ -f $if/dhcp ] && read ibft_dhcp < $if/dhcp
- if [ -n "$ibft_dhcp" -a "$ibft_mode" != "dhcp" ] ; then
- ibft_mode=dhcp
- fi
- if [ "$ibft_mode" = "dhcp" ] ; then
- ibft_ipaddr="0.0.0.0"
- ibft_gateway=
- ibft_mask=
- break
- fi
- [ -f $if/ip-addr ] && read ibft_ipaddr < $if/ip-addr
- [ -f $if/gateway ] && read ibft_gateway < $if/gateway
- [ -f $if/subnet-mask ] && read ibft_mask < $if/subnet-mask
- break
- done
- fi
-
- if [ -z "$optaddr" ] && [ "$ibft_ipaddr" ] ; then
- optaddr=$ibft_ipaddr
- fi
-
- # Check if the interface needs to be configured
- if [ -z "$mode" ] ; then
- if [ "$ibft_mode" != "none" ] ; then
- echo "$mac ibft"
- mode="ibft"
- elif [ -z "$ipaddr" ] ; then
- echo "$mac none"
- mode="none"
- elif [ "$ipaddr" = "0.0.0.0" ] ; then
- echo "$mac dhcp"
- ipaddr=
- mode="dhcp"
- else
- echo "$mac ip $ipaddr"
- mode="static"
- fi
- [ "$dry_run" ] && exit 0
- elif [ "$mode" = "dhcp" ] ; then
- if [ "$ipaddr" = "0.0.0.0" ] ; then
- echo "$mac dhcp"
- exit 0
- fi
- optaddr="0.0.0.0"
- elif [ "$mode" = "static" ] && [ "$ipaddr" = "$optaddr" ] ; then
- echo "$mac ip $ipaddr"
- exit 0
- fi
-
- if [ "$mod" = "be2iscsi" ] ; then
- exit 4
- fi
-
- if ! update_iface_setting $ioe_iface iface.ipaddress "$optaddr" ; then
- echo "Failed to set IP address: $?"
- exit 1
- fi
- if ! update_iface_setting $gen_iface iface.ipaddress "$optaddr" ; then
- echo "Failed to set IP address for generic interface: $?"
- exit 1
- fi
-
- if ! update_iface_setting $ioe_iface iface.gateway "$ibft_gateway" ; then
- echo "Failed to set gateway address: $?"
- exit 1
- fi
-
- if ! update_iface_setting $gen_iface iface.gateway "$ibft_gateway" ; then
- echo "Failed to set gateway address for generic interface: $?"
- exit 1
- fi
-
- if ! update_iface_setting $ioe_iface iface.subnet_mask "$ibft_mask" ; then
- echo "Failed to set subnet mask: $?"
- exit 1
- fi
-
- if ! update_iface_setting $gen_iface iface.subnet_mask "$ibft_mask" ; then
- echo "Failed to set subnet mask for generic interface: $?"
- exit 1
- fi
-
- if [ "$mod" = "qla4xxx" ] ; then
- iscsiadm -m iface -H $mac -o applyall
- fi
- ip link set dev $IFNAME up
-
- exit 0
-
|