b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | #!/bin/sh |
| 2 | # |
| 3 | # iscsi_offload |
| 4 | # |
| 5 | # Configure iSCSI offload engines for use with open-iscsi |
| 6 | # Usage: |
| 7 | # iscsi_offload [-d | -f | -i <ipaddr> | -t ] <nic> |
| 8 | # |
| 9 | # Copyright (c) 2011 Hannes Reinecke, SUSE Labs |
| 10 | # This script is licensed under the GPL. |
| 11 | # |
| 12 | # The script creates an open-iscsi interface definition |
| 13 | # in the style <nic>-<module>, where <nic> matches the |
| 14 | # network interface passed on the commandline. |
| 15 | # If '-t' (test mode) is passed as an option, the script |
| 16 | # will not create nor modify any setting but just print |
| 17 | # the currently active ones. |
| 18 | # |
| 19 | # Currently the script works with Broadcom (bnx2i) and |
| 20 | # Chelsio T3 (cxgbi) iSCSI offload engines. |
| 21 | # Should work with Chelsio T4, but has not been tested. |
| 22 | # ServerEngines (be2iscsi) and QLogic (qla4xxx) can only |
| 23 | # be configured via BIOS, open-iscsi support is still in |
| 24 | # development. |
| 25 | # |
| 26 | |
| 27 | # |
| 28 | # Return codes: |
| 29 | # 0: Success |
| 30 | # 1: Invalid command line parameter |
| 31 | # 2: iSCSI offloading not supported |
| 32 | # 3: Error during module loading |
| 33 | # 4: Cannot configure interface via iscsiadm, use BIOS setup |
| 34 | # 5: internal error running iscsiadm |
| 35 | # |
| 36 | # Output: |
| 37 | # <mac> [none|dhcp|ip <ipaddr>|ibft] |
| 38 | # where |
| 39 | # <mac>: MAC Address of the iSCSI offload engine |
| 40 | # none: No IP configuration set for the iSCSI offload engine |
| 41 | # dhcp: iSCSI offload engine configured for DHCP |
| 42 | # ip: iSCSI offload engine configured with static IP address <ipaddr> |
| 43 | # ibft: iSCSI offload engine configured from iBFT values |
| 44 | # |
| 45 | |
| 46 | # |
| 47 | # Figure out the MAC address of the iSCSI offload engine |
| 48 | # corresponding to a NIC from a given PCI device. |
| 49 | # bnx2 is using one PCI device per port for both network and iSCSI offloading |
| 50 | # cxgb3 is using one PCI device for everything. |
| 51 | # |
| 52 | iscsi_macaddress_from_pcidevice() |
| 53 | { |
| 54 | local path=$1 |
| 55 | local if=$2 |
| 56 | local h |
| 57 | local host |
| 58 | |
| 59 | for h in $path/host* ; do |
| 60 | if [ -d "$h" ] ; then |
| 61 | host=${h##*/} |
| 62 | read netdev < /sys/class/iscsi_host/$host/netdev |
| 63 | if [ "$netdev" = "$IFNAME" ] ; then |
| 64 | read mac < /sys/class/iscsi_host/$host/hwaddress |
| 65 | if [ "$mac" != "00:00:00:00:00:00" ] ; then |
| 66 | echo "$mac" |
| 67 | fi |
| 68 | break; |
| 69 | fi |
| 70 | fi |
| 71 | done |
| 72 | } |
| 73 | |
| 74 | # |
| 75 | # Figure out the MAC address of the iSCSI offload engine |
| 76 | # corresponding to a NIC from a given PCI function. |
| 77 | # It is assumed that the MAC address of the iSCSI offload |
| 78 | # engine is equal of the MAC address of the NIC plus one. |
| 79 | # Suitable for be2iscsi and qla4xxx |
| 80 | # |
| 81 | iscsi_macaddress_from_pcifn() |
| 82 | { |
| 83 | local path=$1 |
| 84 | local if=$2 |
| 85 | local h |
| 86 | local host |
| 87 | local ifmac |
| 88 | |
| 89 | ifmac=$(ip addr show dev $if | sed -n 's/ *link\/ether \(.*\) brd.*/\1/p') |
| 90 | m5=$(( 0x${ifmac##*:} )) |
| 91 | m5=$(( $m5 + 1 )) |
| 92 | ifmac=$(printf "%s:%02x" ${ifmac%:*} $m5) |
| 93 | for host in /sys/class/iscsi_host/host* ; do |
| 94 | if [ -L "$host" ] ; then |
| 95 | read mac < $host/hwaddress |
| 96 | if [ "$mac" = "$ifmac" ] ; then |
| 97 | echo "$mac" |
| 98 | break; |
| 99 | fi |
| 100 | fi |
| 101 | done |
| 102 | } |
| 103 | |
| 104 | update_iface_setting() { |
| 105 | local iface="$1" |
| 106 | local name="$2" |
| 107 | local value="$3" |
| 108 | |
| 109 | iface_value=$(iscsiadm -m iface -I $iface | sed -n "s/$name = \(.*\)/\1/p") |
| 110 | if [ "$iface_value" = "<empty>" ] ; then |
| 111 | iface_value= |
| 112 | fi |
| 113 | if [ "$iface_value" != "$value" ] ; then |
| 114 | if ! iscsiadm -m iface -I $iface -o update -n "$name" -v "$value" ; then |
| 115 | return 1 |
| 116 | fi |
| 117 | fi |
| 118 | return 0 |
| 119 | } |
| 120 | |
| 121 | while getopts di:t options ; do |
| 122 | case $options in |
| 123 | d ) mode=dhcp;; |
| 124 | i ) mode=static |
| 125 | optaddr=$OPTARG |
| 126 | ;; |
| 127 | f ) mode=firmware;; |
| 128 | t ) dry_run=1;; |
| 129 | ?) printf "Usage: %s [-d|-t|-i ipaddr|-f] ifname\n" $0 |
| 130 | exit 1;; |
| 131 | esac |
| 132 | done |
| 133 | shift $(($OPTIND - 1)) |
| 134 | |
| 135 | IFNAME=$1 |
| 136 | ibft_mode="none" |
| 137 | |
| 138 | if [ -z "$IFNAME" ] ; then |
| 139 | echo "No interface specified" |
| 140 | exit 1 |
| 141 | fi |
| 142 | |
| 143 | if [ "$dry_run" ] ; then |
| 144 | if [ "$mode" = "dhcp" ] ; then |
| 145 | echo "'-t' specified, ignoring '-d'" |
| 146 | mode= |
| 147 | elif [ "$mode" = "static" ] ; then |
| 148 | echo "'-t' specified, ignoring '-s'" |
| 149 | mode= |
| 150 | fi |
| 151 | fi |
| 152 | |
| 153 | if [ ! -L /sys/class/net/$IFNAME ] ; then |
| 154 | echo "Interface $IFNAME not found" |
| 155 | exit 1 |
| 156 | fi |
| 157 | |
| 158 | if [ "$optaddr" ] && ! ip route get $optaddr ; then |
| 159 | echo "Invalid IP address $optaddr" |
| 160 | exit 1 |
| 161 | fi |
| 162 | if [ "$dry_run" ] ; then |
| 163 | mode= |
| 164 | fi |
| 165 | |
| 166 | |
| 167 | ifpath=$(cd -P /sys/class/net/$IFNAME; echo $PWD) |
| 168 | pcipath=$(cd -P $ifpath/device; echo $PWD) |
| 169 | |
| 170 | if [ -d $pcipath ] ; then |
| 171 | drvlink=$(readlink $pcipath/driver) |
| 172 | driver=${drvlink##*/} |
| 173 | fi |
| 174 | |
| 175 | if [ -z "$driver" ] ; then |
| 176 | echo "No driver found for interface $IFNAME" |
| 177 | exit 1 |
| 178 | fi |
| 179 | |
| 180 | case "$driver" in |
| 181 | bnx2*) |
| 182 | mod=bnx2i |
| 183 | ;; |
| 184 | cxgb*) |
| 185 | mod=cxgb3i |
| 186 | ;; |
| 187 | be2*) |
| 188 | mod=be2iscsi |
| 189 | ;; |
| 190 | qla*) |
| 191 | mod=qla4xxx |
| 192 | ;; |
| 193 | esac |
| 194 | |
| 195 | if [ -z "$mod" ] ; then |
| 196 | echo "iSCSI offloading not supported on interface $IFNAME" |
| 197 | exit 2 |
| 198 | fi |
| 199 | |
| 200 | # Check if the required modules are already loaded |
| 201 | loaded=$(sed -n "/^$mod/p" /proc/modules) |
| 202 | if [ -z "$loaded" ] ; then |
| 203 | modprobe $mod |
| 204 | fi |
| 205 | |
| 206 | loaded=$(sed -n "/^$mod/p" /proc/modules) |
| 207 | if [ -z "$loaded" ] ; then |
| 208 | echo "Loading of $mod.ko failed, please check dmesg" |
| 209 | exit 3 |
| 210 | fi |
| 211 | |
| 212 | # Get the correct MAC address for the various devices |
| 213 | if [ "$mod" = "bnx2i" ] ; then |
| 214 | mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME) |
| 215 | elif [ "$mod" = "cxgb3i" ] ; then |
| 216 | mac=$(iscsi_macaddress_from_pcidevice $pcipath $IFNAME) |
| 217 | elif [ "$mod" = "be2iscsi" ] ; then |
| 218 | mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) |
| 219 | elif [ "$mod" = "qla4xxx" ] ; then |
| 220 | mac=$(iscsi_macaddress_from_pcifn $pcipath $IFNAME) |
| 221 | fi |
| 222 | |
| 223 | if [ -z "$mac" ] ; then |
| 224 | echo "iSCSI offloading not supported on interface $IFNAME" |
| 225 | exit 2 |
| 226 | fi |
| 227 | |
| 228 | gen_iface="$mod.$mac" |
| 229 | ioe_iface="${IFNAME}-${mod}" |
| 230 | |
| 231 | # Get existing settings |
| 232 | if iscsiadm -m iface -I $ioe_iface > /dev/null 2>&1 ; then |
| 233 | ioe_mac=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.hwaddress = \(.*\)/\1/p") |
| 234 | ioe_mod=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.transport_name = \(.*\)/\1/p") |
| 235 | ipaddr=$(iscsiadm -m iface -I $ioe_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p") |
| 236 | if [ "$ipaddr" == "<empty>" ] ; then |
| 237 | ipaddr= |
| 238 | fi |
| 239 | elif [ "$mod" = "be2iscsi" ] ; then |
| 240 | ioe_mac=$mac |
| 241 | ioe_mod=$mod |
| 242 | else |
| 243 | # Create new interface |
| 244 | iscsiadm -m iface -I $ioe_iface --op=new 2> /dev/null |
| 245 | ioe_mac= |
| 246 | ioe_mod= |
| 247 | ipaddr= |
| 248 | fi |
| 249 | |
| 250 | if [ -z "$dry_run" ] ; then |
| 251 | if [ "$ioe_mac" != "$mac" ] ; then |
| 252 | if [ -n "$ioe_mac" ] ; then |
| 253 | echo "Warning: Updating MAC address on iface $ioe_iface" |
| 254 | fi |
| 255 | update_iface_setting $ioe_iface iface.hwaddress "$mac" |
| 256 | fi |
| 257 | |
| 258 | if [ "$ioe_mod" != "$mod" ] ; then |
| 259 | if [ -n "$ioe_mod" ] ; then |
| 260 | echo "Warning: Update transport on iface $ioe_iface" |
| 261 | fi |
| 262 | update_iface_setting $ioe_iface iface.transport_name "$mod" |
| 263 | fi |
| 264 | elif [ -z "$ipaddr" ] ; then |
| 265 | ipaddr=$(iscsiadm -m iface -I $gen_iface 2> /dev/null| sed -n "s/iface\.ipaddress = \(.*\)/\1/p") |
| 266 | if [ "$ipaddr" = "<empty>" ] ; then |
| 267 | ipaddr= |
| 268 | fi |
| 269 | elif [ "$ioe_mod" != "$mod" ] ; then |
| 270 | echo "Warning: Transport mismatch on iface $ioe_iface: $ioe_mod should be $mod" |
| 271 | fi |
| 272 | |
| 273 | # Check iBFT setting |
| 274 | for d in /sys/firmware/* ; do |
| 275 | [ -d $d ] || continue |
| 276 | [ -d $d/ethernet0 ] || continue |
| 277 | iboot_dir=$d |
| 278 | done |
| 279 | if [ -n "$iboot_dir" ] && [ -d "$iboot_dir" ] ; then |
| 280 | for if in ${iboot_dir}/ethernet* ; do |
| 281 | read ibft_mac < $if/mac |
| 282 | [ "$ibft_mac" = "$mac" ] || continue |
| 283 | ibft_origin=0 |
| 284 | [ -f ${if}/origin ] && read ibft_origin < $if/origin |
| 285 | if [ "$ibft_origin" -eq 1 ] ; then |
| 286 | ibft_mode="static" |
| 287 | elif [ "$ibft_origin" -eq 3 ] ; then |
| 288 | ibft_mode="dhcp" |
| 289 | fi |
| 290 | [ -f $if/dhcp ] && read ibft_dhcp < $if/dhcp |
| 291 | if [ -n "$ibft_dhcp" -a "$ibft_mode" != "dhcp" ] ; then |
| 292 | ibft_mode=dhcp |
| 293 | fi |
| 294 | if [ "$ibft_mode" = "dhcp" ] ; then |
| 295 | ibft_ipaddr="0.0.0.0" |
| 296 | ibft_gateway= |
| 297 | ibft_mask= |
| 298 | break |
| 299 | fi |
| 300 | [ -f $if/ip-addr ] && read ibft_ipaddr < $if/ip-addr |
| 301 | [ -f $if/gateway ] && read ibft_gateway < $if/gateway |
| 302 | [ -f $if/subnet-mask ] && read ibft_mask < $if/subnet-mask |
| 303 | break |
| 304 | done |
| 305 | fi |
| 306 | |
| 307 | if [ -z "$optaddr" ] && [ "$ibft_ipaddr" ] ; then |
| 308 | optaddr=$ibft_ipaddr |
| 309 | fi |
| 310 | |
| 311 | # Check if the interface needs to be configured |
| 312 | if [ -z "$mode" ] ; then |
| 313 | if [ "$ibft_mode" != "none" ] ; then |
| 314 | echo "$mac ibft" |
| 315 | mode="ibft" |
| 316 | elif [ -z "$ipaddr" ] ; then |
| 317 | echo "$mac none" |
| 318 | mode="none" |
| 319 | elif [ "$ipaddr" = "0.0.0.0" ] ; then |
| 320 | echo "$mac dhcp" |
| 321 | ipaddr= |
| 322 | mode="dhcp" |
| 323 | else |
| 324 | echo "$mac ip $ipaddr" |
| 325 | mode="static" |
| 326 | fi |
| 327 | [ "$dry_run" ] && exit 0 |
| 328 | elif [ "$mode" = "dhcp" ] ; then |
| 329 | if [ "$ipaddr" = "0.0.0.0" ] ; then |
| 330 | echo "$mac dhcp" |
| 331 | exit 0 |
| 332 | fi |
| 333 | optaddr="0.0.0.0" |
| 334 | elif [ "$mode" = "static" ] && [ "$ipaddr" = "$optaddr" ] ; then |
| 335 | echo "$mac ip $ipaddr" |
| 336 | exit 0 |
| 337 | fi |
| 338 | |
| 339 | if [ "$mod" = "be2iscsi" ] ; then |
| 340 | exit 4 |
| 341 | fi |
| 342 | |
| 343 | if ! update_iface_setting $ioe_iface iface.ipaddress "$optaddr" ; then |
| 344 | echo "Failed to set IP address: $?" |
| 345 | exit 1 |
| 346 | fi |
| 347 | if ! update_iface_setting $gen_iface iface.ipaddress "$optaddr" ; then |
| 348 | echo "Failed to set IP address for generic interface: $?" |
| 349 | exit 1 |
| 350 | fi |
| 351 | |
| 352 | if ! update_iface_setting $ioe_iface iface.gateway "$ibft_gateway" ; then |
| 353 | echo "Failed to set gateway address: $?" |
| 354 | exit 1 |
| 355 | fi |
| 356 | |
| 357 | if ! update_iface_setting $gen_iface iface.gateway "$ibft_gateway" ; then |
| 358 | echo "Failed to set gateway address for generic interface: $?" |
| 359 | exit 1 |
| 360 | fi |
| 361 | |
| 362 | if ! update_iface_setting $ioe_iface iface.subnet_mask "$ibft_mask" ; then |
| 363 | echo "Failed to set subnet mask: $?" |
| 364 | exit 1 |
| 365 | fi |
| 366 | |
| 367 | if ! update_iface_setting $gen_iface iface.subnet_mask "$ibft_mask" ; then |
| 368 | echo "Failed to set subnet mask for generic interface: $?" |
| 369 | exit 1 |
| 370 | fi |
| 371 | |
| 372 | if [ "$mod" = "qla4xxx" ] ; then |
| 373 | iscsiadm -m iface -H $mac -o applyall |
| 374 | fi |
| 375 | ip link set dev $IFNAME up |
| 376 | |
| 377 | exit 0 |
| 378 | |