├── config.h ├── fns.h ├── .gitignore ├── aoe-discover.in ├── sos-linux.8 ├── pkg └── rhel6 │ ├── SOURCES │ └── 60-aoe.rules │ └── SPECS │ └── aoetools.spec ├── aoe-revalidate.in ├── aoe-version.8 ├── aoe-revalidate.8 ├── HACKING ├── coraid-update.8 ├── aoe-flush.in ├── sos-linux ├── aoe-interfaces.in ├── aoe-mkshelf.in ├── aoetools.8 ├── aoe-flush.8 ├── aoe-mkdevs ├── devnodes.txt ├── aoe-version ├── aoe-discover.8 ├── dat.h ├── linux.c ├── README ├── aoe-stat.in ├── aoe-mkshelf.8 ├── aoe-mkdevs.8 ├── coraid-update ├── aoecfg.8 ├── aoe-interfaces.8 ├── Makefile ├── aoe-sancheck.8 ├── aoe-stat.8 ├── aoecfg.c ├── aoeping.8 ├── NEWS ├── aoeping.c ├── aoe-sancheck.c └── COPYING /config.h: -------------------------------------------------------------------------------- 1 | #define _FILE_OFFSET_BITS 64 2 | -------------------------------------------------------------------------------- /fns.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2009, CORAID, Inc., and licensed under GPL v.2. */ 2 | int dial(char *eth); 3 | int getea(int s, char *name, uchar *ea); 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | -------------------------------------------------------------------------------- /aoe-discover.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # aoe-discover - trigger an AoE device discovery 3 | # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | zero=`basename $0` 6 | f=@devdir@/discover 7 | 8 | if ! test -w $f; then 9 | echo 1>&2 $zero: $f does not exist or is not writeable. 10 | exit 1 11 | fi 12 | if ! test -c $f; then 13 | exec 1>&2 14 | echo "$zero: $f is not a character device file" 15 | echo "$zero: use udev or aoe-mkdevs to create it" 16 | exit 1 17 | fi 18 | echo > $f 19 | -------------------------------------------------------------------------------- /sos-linux.8: -------------------------------------------------------------------------------- 1 | .TH sos-linux 8 2 | .SH NAME 3 | sos-linux \- create file containing AoE-related information 4 | .SH SYNOPSIS 5 | .nf 6 | .B sos-linux 7 | .fi 8 | .SH DESCRIPTION 9 | The 10 | .I sos-linux 11 | script creates a dated output file in the home directory of the user 12 | running it. 13 | .PP 14 | The filename is printed on the standard output. 15 | .PP 16 | The file contains information about the local system that is likely 17 | to be relevant to its use as an AoE initiator. 18 | .SH "SEE ALSO" 19 | .IR aoe-stat (8), 20 | .IR aoetools (8). 21 | .SH AUTHOR 22 | Ed L. Cashin (ecashin@coraid.com) 23 | -------------------------------------------------------------------------------- /pkg/rhel6/SOURCES/60-aoe.rules: -------------------------------------------------------------------------------- 1 | # These rules tell udev what device nodes to create for aoe support. 2 | 3 | # aoe char devices 4 | SUBSYSTEM=="aoe", KERNEL=="discover", NAME="etherd/%k", GROUP="disk", MODE="0220" 5 | SUBSYSTEM=="aoe", KERNEL=="err", NAME="etherd/%k", GROUP="disk", MODE="0440" 6 | SUBSYSTEM=="aoe", KERNEL=="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220" 7 | SUBSYSTEM=="aoe", KERNEL=="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220" 8 | SUBSYSTEM=="aoe", KERNEL=="flush", NAME="etherd/%k", GROUP="disk", MODE="0220" 9 | 10 | # aoe block devices 11 | KERNEL=="etherd*", NAME="%k", GROUP="disk" 12 | -------------------------------------------------------------------------------- /aoe-revalidate.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # aoe-revalidate - ask aoe driver to query AoE target 3 | # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | zero=`basename $0` 6 | f=@devdir@/revalidate 7 | 8 | if test -z "$*"; then 9 | echo 1>&2 Usage: $zero 'e{major}.{minor}' 10 | exit 1 11 | fi 12 | if ! test -w $f; then 13 | echo 1>&2 $zero: $f does not exist or is not writeable 14 | exit 1 15 | fi 16 | if ! test -c $f; then 17 | exec 1>&2 18 | echo "$zero: $f is not a character device file" 19 | echo "$zero: use udev or aoe-mkdevs to create it" 20 | exit 1 21 | fi 22 | echo "$*" > $f || { 23 | echo "$zero: revalidate failed" 1>&2 24 | exit 1 25 | } 26 | 27 | -------------------------------------------------------------------------------- /aoe-version.8: -------------------------------------------------------------------------------- 1 | .TH aoe-version 8 2 | .SH NAME 3 | aoe-version \- print AoE-related software version information 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-version 7 | .fi 8 | .SH DESCRIPTION 9 | The 10 | .I aoe-version 11 | script collects information on running and installed ATA over Ethernet 12 | software, displaying a summary. 13 | .SH EXAMPLE 14 | .IP 15 | .EX 16 | .nf 17 | ellijay:~# aoe-version 18 | aoetools: 17 19 | installed aoe driver: 50 20 | running aoe driver: 50 21 | .fi 22 | .EE 23 | .SH "SEE ALSO" 24 | .IR aoe-discover (8), 25 | .IR aoe-interfaces (8), 26 | .IR aoetools (8), 27 | .IR aoe-stat (8). 28 | .SH AUTHOR 29 | Ed L. Cashin (ecashin@coraid.com) 30 | -------------------------------------------------------------------------------- /aoe-revalidate.8: -------------------------------------------------------------------------------- 1 | .TH aoe-revalidate 8 2 | .SH NAME 3 | aoe-revalidate \- revalidate the disk size of an aoe device 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-revalidate e{major}.{minor} 7 | .fi 8 | .SH DESCRIPTION 9 | The 10 | .I aoe-revalidate 11 | command tells the aoe driver to revalidate the disk size of an open aoe device. 12 | Normally the aoe driver will only acknowledge changes in an aoe device's 13 | disk size when the aoe device is not open. 14 | .PP 15 | It should be noted that if an aoe device's disk size shrinks in revalidation 16 | any users may become hopelessly confused when their resumed I/O starts to fail. 17 | .SH EXAMPLE 18 | .EX 19 | .nf 20 | nai# aoe-stat | grep e1.9 21 | e1.9 82.348GB eth0 up 22 | nai# < /dev/etherd/e1.9 sleep 600 & 23 | [1] 13006 24 | nai# aoe-revalidate e1.9 25 | nai# aoe-stat | grep e1.9 26 | e1.9 164.696GB eth0 up 27 | .fi 28 | .EE 29 | .SH "SEE ALSO" 30 | .IR aoe-stat (8), 31 | .IR aoetools (8). 32 | .SH AUTHOR 33 | Sam Hopkins (sah@coraid.com) 34 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | Contributing 2 | 3 | Thanks for your interest in contributing to the aoetools. The best 4 | way to submit proposed changes is in plain-text "patches". These 5 | patches are generated by the diff program. 6 | 7 | Patches should be clean (to the point and easy to read) and should do 8 | one thing. Send multiple patches if necessary. Patches should be 9 | generated with "diff -uprN" if possible, and should be designed to be 10 | applied with "patch -p1". 11 | 12 | 13 | Design note: 14 | 15 | The aoe-mkdevs and aoe-mkshelf scripts are expected to work with 16 | special device files forever, but the aoe-discover script will likely 17 | someday use sysfs or something similar instead of 18 | /dev/etherd/discover. The same goes for aoe-interfaces. For that 19 | reason, there is no runtime interface for giving aoe-discover an 20 | alternative to /dev/etherd at runtime. Instead, the device directory 21 | is set once and for all by make. That way, the user interface won't 22 | change or become obsolete when aoe-discover stops using 23 | /dev/etherd/discover. 24 | -------------------------------------------------------------------------------- /coraid-update.8: -------------------------------------------------------------------------------- 1 | .TH coraid-update 8 2 | .SH NAME 3 | coraid-update \- upload an update file to a CORAID appliance 4 | .SH SYNOPSIS 5 | .nf 6 | .B coraid-update {update file} {AoE device} 7 | .fi 8 | .SH DESCRIPTION 9 | The 10 | .I coraid-update 11 | script performs a few sanity checks before copying the local 12 | update 13 | file to the remote update AoE target on the CORAID appliance. 14 | .PP 15 | Two arguments are provided: 1) the name of the update file 16 | to be uploaded, and 2) the special block device file corresponding 17 | to the 18 | update target, e.g., \fI/dev/etherd/e100.40\fP. 19 | .PP 20 | It generates no output and exits with a zero status when the update 21 | file has been successfully uploaded 22 | to the update target on the appliance. Otherwise, an error message is 23 | printed to standard error and \fI coraid-update\fR exits with a 24 | non-zero status. 25 | .SH "SEE ALSO" 26 | .IR aoe-discover (8), 27 | .IR aoe-interfaces (8), 28 | .IR aoe-stat (8), 29 | .IR aoetools (8), 30 | .IR udev (7). 31 | .SH AUTHOR 32 | Ed L. Cashin (ecashin@coraid.com) 33 | -------------------------------------------------------------------------------- /aoe-flush.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # aoe-flush - ask aoe driver to forget about devices 3 | # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | zero="`basename $0`" 6 | f="@devdir@/flush" 7 | spec="" 8 | 9 | if ! test -w "$f"; then 10 | echo 1>&2 "$zero: $f does not exist or is not writeable." 11 | exit 1 12 | fi 13 | if ! test -c $f; then 14 | exec 1>&2 15 | echo "$zero: $f is not a character device file" 16 | echo "$zero: use udev or aoe-mkdevs to create it" 17 | exit 1 18 | fi 19 | 20 | # make sure that each device in the whitespace-separated 21 | # list exists 22 | verify_devs () { 23 | err="" 24 | for d; do 25 | aoe-stat | 26 | awk -vd="$d" '$1==d{print $1}' | 27 | test "`cat`" || { 28 | exec 2>&1 29 | echo "$zero Error: \"$d\" is not an aoe device" 30 | err="$err $d" 31 | } 32 | done 33 | test ! "$err" 34 | } 35 | 36 | err="" 37 | if test "$1"; then 38 | if test "$1" = "-a"; then 39 | spec=all 40 | else 41 | spec="$*" 42 | verify_devs $spec || exit 1 43 | fi 44 | for i in $spec; do 45 | printf "$i" > "$f" || { 46 | echo 1>&2 "$zero: flush failed" 47 | err="$err $i" 48 | } 49 | done 50 | else 51 | echo > "$f" || err=no_args 52 | fi 53 | if test "$err"; then 54 | exit 1 55 | fi 56 | -------------------------------------------------------------------------------- /sos-linux: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | me="`basename $0`" 4 | outf="$HOME/sos-`hostname`-`date +%Y%m%d-%H%M%S`.txt" 5 | 6 | if test "`whoami`" != "root"; then 7 | echo "$me: please run $me as root" 1>&2 8 | exit 1 9 | fi 10 | echo "$me: output file is $outf" 11 | 12 | exec > $outf 13 | exec 2>&1 14 | set -x 15 | uname -a 16 | grep . /etc/*release* /etc/*version* | sed 50q 17 | find /sys/module/aoe -name version | xargs cat 18 | cat /proc/mounts 19 | aoe-version 20 | aoe-stat 21 | cat /proc/mdstat 22 | pvs 23 | ifconfig -a 24 | free 25 | dmesg | tail -n 50 26 | lspci 27 | set +x 28 | for i in `aoe-stat | awk '{print $3}' | sed 's!,! !g'`; do 29 | echo ethtool -S $i 30 | done | sort | uniq | sh -x 31 | # top -b -n 1 32 | 33 | # check for old-style sysfs-exported debug information, ignoring errors 34 | grep . /sys/block/etherd*/debug /dev/null 35 | 36 | # check for new-style debugfs-exported debug information, ignoring errors 37 | dmnt=/sys/kernel/debug 38 | didmount= 39 | mounted=`awk '$3=="debugfs"{print $2}' /proc/mounts` 40 | if test "x$mounted" = "x" && mount -t debugfs none "$dmnt"; then 41 | didmount="$dmnt" 42 | mounted="$dmnt" 43 | fi 44 | cd "$mounted"/aoe && grep . e[0-9]*.*[0-9] 45 | cd / 46 | if test "x$didmount" != "x"; then 47 | umount "$didmount" 48 | fi 49 | exit 0 50 | -------------------------------------------------------------------------------- /aoe-interfaces.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # aoe-interfaces - set or list the allowed AoE network interfaces 3 | # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | zero="`basename $0`" 6 | devf=@devdir@/interfaces 7 | sysf=/sys/module/aoe/parameters/aoe_iflist 8 | 9 | if test -z "$*"; then 10 | if test -r "$sysf"; then 11 | cat "$sysf" 12 | else 13 | # can't read from interfaces device 14 | false 15 | fi 16 | exit 17 | fi 18 | 19 | if test "$1" = "-c"; then 20 | shift 21 | if test "$#" != "0"; then 22 | echo "$zero Error: -c flag takes no arguments" 1>&2 23 | exit 1 24 | fi 25 | fi 26 | netifs="$*" 27 | 28 | err=no 29 | for i in $netifs; do 30 | test -d "/sys/class/net/$i" || { 31 | echo "$zero Error: \"$i\" is not a network interface" 1>&2 32 | err=yes 33 | } 34 | done 35 | if test "$err" = "yes"; then 36 | exit 1 37 | fi 38 | 39 | if test -w "$sysf"; then 40 | printf '%s\0' "$netifs" > "$sysf" 41 | else 42 | if test ! -w "$devf"; then 43 | echo 1>&2 "$zero: $devf does not exist or is not writeable." 44 | exit 1 45 | fi 46 | if test ! -c "$devf"; then 47 | exec 1>&2 48 | echo "$zero: $devf is not a character device file" 49 | echo "$zero: use udev or aoe-mkdevs to create it" 50 | exit 1 51 | fi 52 | printf '%s\0' "$netifs" > "$devf" 53 | fi 54 | -------------------------------------------------------------------------------- /aoe-mkshelf.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # aoe-mkshelf - device nodes for one shelf without udev 3 | # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | zero=`basename $0` 6 | 7 | if test "$#" != "2"; then 8 | echo "Usage: $zero {dir} {shelfaddress}" 1>&2 9 | echo " n_partitions=16 $zero {dir} {shelfaddress}" 1>&2 10 | exit 1 11 | fi 12 | dyn=/sys/module/aoe/parameters/aoe_dyndevs 13 | if test -r "$dyn" && test "`cat $dyn`" = 1; then 14 | cat 1>&2 <&2 < 10 | Version: 36 11 | Release: 1%{dist} 12 | URL: http://aoetools.sourceforge.net/ 13 | Source0: %{name}-%{version}.tar.gz 14 | Source1: 60-aoe.rules 15 | License: GPLv2 16 | Group: Application/System 17 | 18 | %description 19 | The command-line utilities for using the aoe driver to work with 20 | ATA over Ethernet storage targets on a Linux system. 21 | 22 | %define debug_package %{nil} 23 | 24 | %prep 25 | %setup -n %{name}-%{version} 26 | 27 | %build 28 | make SBINDIR=%{sbind} MANDIR=%{mand} 29 | 30 | %install 31 | mkdir -p -m 755 %{sbind}/ 32 | mkdir -p -m 755 %{mand}/man8/ 33 | make install SBINDIR=%{sbind} MANDIR=%{mand} 34 | mkdir -p -m 755 %{udevrulesd}/ 35 | install -m 644 %{SOURCE1} %{udevrulesd} 36 | 37 | %files 38 | %defattr(-,root,root) 39 | %doc %docfiles 40 | %attr(0755,root,root) %{_sbindir}/* 41 | %{_mandir}/man8/* 42 | %config %{_sysconfdir}/udev/rules.d/* 43 | 44 | %changelog 45 | * Thu Aug 15 2013 Ed Cashin - 36-1 46 | - Update for v36 47 | 48 | * Wed Jul 10 2013 Ed Cashin - 35-1 49 | - Initial package for aoetools v35 plus udev rules 50 | -------------------------------------------------------------------------------- /aoetools.8: -------------------------------------------------------------------------------- 1 | .TH aoetools 8 2 | .SH NAME 3 | aoetools \- utilities for AoE on systems running Linux 2.6 and up 4 | .SH DESCRIPTION 5 | The 6 | .I aoetools 7 | package contains scripts and commands that interact with, 8 | support, and supplement the 9 | aoe driver in the Linux kernel. 10 | .TP 11 | .BI aoe-discover 12 | tell aoe driver to discover AoE devices 13 | .TP 14 | .BI aoe-flush 15 | flush the down devices out of the aoe driver 16 | .TP 17 | .BI aoe-interfaces 18 | restrict aoe driver to specified network interfaces 19 | .TP 20 | .BI aoe-mkdevs 21 | create special device files for system without udev 22 | .TP 23 | .BI aoe-mkshelf 24 | create device files for one shelf address for system without udev 25 | .TP 26 | .BI aoe-revalidate 27 | revalidate the disk size of an aoe device 28 | .TP 29 | .BI aoe-stat 30 | collate and present information about AoE storage 31 | .TP 32 | .BI aoe-version 33 | display version numbers of AoE-related software 34 | .TP 35 | .BI coraid-update 36 | send updates to CORAID appliances 37 | .TP 38 | .BI sos-linux 39 | collect AoE-related information about the localhost 40 | .TP 41 | .BI aoe-sancheck 42 | perform an analysis of the AoE storage network 43 | .SH "SEE ALSO" 44 | .IR aoe-discover (8), 45 | .IR aoe-flush (8), 46 | .IR aoe-interfaces (8), 47 | .IR aoe-mkdevs (8), 48 | .IR aoe-mkshelf (8), 49 | .IR aoe-revalidate (8), 50 | .IR aoe-stat (8), 51 | .IR aoe-version (8), 52 | .IR aoecfg (8), 53 | .IR aoeping (8), 54 | .IR coraid-update (8), 55 | .IR sos-linux (8), 56 | .IR aoe-sancheck (8), 57 | .IR udev (7). 58 | -------------------------------------------------------------------------------- /aoe-flush.8: -------------------------------------------------------------------------------- 1 | .TH aoe-flush 8 2 | .SH NAME 3 | aoe-flush \- flush the down devices out of the aoe driver 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-flush [-a] 7 | .B aoe-flush dev1 [dev2 ...] 8 | .fi 9 | .SH DESCRIPTION 10 | The 11 | .I aoe-flush 12 | command tells the aoe driver to remove devices from the system and 13 | forget about them. Normally the aoe driver will remember all devices it has 14 | seen until the module is unloaded. By default, 15 | .I aoe-flush 16 | will only flush 17 | downed devices. With the \fB-a\fP flag all devices are candidates for removal. 18 | .PP 19 | .I aoe-flush 20 | will not remove devices that are in use. This includes devices in the 21 | closewait state or those in the process of being installed. 22 | .PP 23 | By specifying a series of specific aoe devices, e.g., \fBe7.0 e3.2\fP, 24 | it is possible to ask the aoe driver to forget these devices. This 25 | feature may be convenient after a temporary AoE target is no longer 26 | being used. 27 | .SH OPTIONS 28 | .TP 29 | \fB-a\fP 30 | The \fB-a\fP option tells the aoe driver to forget all unused devices. 31 | .SH EXAMPLE 32 | .EX 33 | .nf 34 | nai# aoe-stat | grep e12.0 35 | e12.0 0.000GB eth1 down 36 | nai# aoe-flush 37 | nai# aoe-stat | grep e12.0 38 | .fi 39 | .EE 40 | .SH BUGS 41 | Flushed devices may reappear when they are discovered by the periodic discovery 42 | beacon. 43 | .I aoe-discover 44 | may be used to force this behaviour. 45 | .SH "SEE ALSO" 46 | .IR aoe-stat (8), 47 | .IR aoe-discover (8), 48 | .IR aoetools (8). 49 | .SH AUTHOR 50 | Sam Hopkins (sah@coraid.com) 51 | -------------------------------------------------------------------------------- /aoe-mkdevs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # aoe-mkdevs - make static device nodes on systems without udev 3 | # Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | n_shelves=${n_shelves:-10} 6 | n_partitions=${n_partitions:-16} 7 | 8 | if test "$#" != "1"; then 9 | echo "Usage: `basename $0` {dir}" 1>&2 10 | echo " n_partitions=16 `basename $0` {dir}" 1>&2 11 | exit 1 12 | fi 13 | dir=$1 14 | zero="`basename $0`" 15 | MAJOR=152 16 | 17 | dyn=/sys/module/aoe/parameters/aoe_dyndevs 18 | if test -r "$dyn" && test "`cat $dyn`" = 1; then 19 | cat 1>&2 <&2 < /dev/null && test ! -r aoe && echo yes; } || echo no` 12 | if test "$a" = "yes"; then 13 | cd "$wd" 14 | break 15 | fi 16 | done 17 | # The aoe module isn't guaranteed to be in the location below, 18 | # but if we only try to use it when each of the directories 19 | # above was not usable, we shouldn't use the hard-coded location 20 | # often. 21 | aoe=aoe 22 | if test -r ./aoe; then 23 | aoe="/lib/modules/`uname -r`/kernel/drivers/block/aoe/aoe.ko" 24 | fi 25 | 26 | # standalone aoe drivers have a module parameter "version" 27 | installed="`modinfo \"$aoe\" 2>/dev/null | awk '/srcversion/ {next} /^parm:.*version:aoe module/ {print $NF; exit 0}'`" 28 | if test -z "$installed"; then 29 | # Recent kernels have a "version" of their own, so 30 | # they didn't want our module parameter, so we look 31 | # for that, too, in case user is using kernel.org driver. 32 | installed="`modinfo \"$aoe\" 2>/dev/null | awk '/^version:/ {print $NF; exit 0}'`" 33 | fi 34 | if test "$?" != "0" || test -z "$installed"; then 35 | installed="(unknown)" 36 | fi 37 | 38 | if test -d /sys/module/aoe; then 39 | running="`find /sys/module/aoe -name version | sed 1q | xargs cat`" 40 | if test "$?" != "0"; then 41 | running="(unknown)" 42 | fi 43 | else 44 | running="(none)" 45 | fi 46 | 47 | while read val desc; do 48 | printf "%22s:\t%s\n" "$desc" "$val" 49 | done < 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include /* for the glibc version number */ 12 | #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1 13 | #include 14 | #include /* the L2 protocols */ 15 | #else 16 | #include 17 | #include 18 | #include /* The L2 protocols */ 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "dat.h" 29 | #include "fns.h" 30 | 31 | static int 32 | getindx(int s, char *name) // return the index of device 'name' 33 | { 34 | struct ifreq xx; 35 | int n; 36 | 37 | strcpy(xx.ifr_name, name); 38 | n = ioctl(s, SIOCGIFINDEX, &xx); 39 | if (n == -1) 40 | return -1; 41 | return xx.ifr_ifindex; 42 | } 43 | 44 | int 45 | dial(char *eth) // get us a raw connection to an interface 46 | { 47 | int i; 48 | int n, s; 49 | struct sockaddr_ll sa; 50 | enum { aoe_type = 0x88a2 }; 51 | 52 | memset(&sa, 0, sizeof sa); 53 | s = socket(PF_PACKET, SOCK_RAW, htons(aoe_type)); 54 | if (s == -1) { 55 | perror("got bad socket"); 56 | return -1; 57 | } 58 | i = getindx(s, eth); 59 | sa.sll_family = AF_PACKET; 60 | sa.sll_protocol = htons(0x88a2); 61 | sa.sll_ifindex = i; 62 | n = bind(s, (struct sockaddr *)&sa, sizeof sa); 63 | if (n == -1) { 64 | perror("bind funky"); 65 | return -1; 66 | } 67 | return s; 68 | } 69 | 70 | int 71 | getea(int s, char *name, uchar *ea) 72 | { 73 | struct ifreq xx; 74 | int n; 75 | 76 | strcpy(xx.ifr_name, name); 77 | n = ioctl(s, SIOCGIFHWADDR, &xx); 78 | if (n == -1) { 79 | perror("Can't get hw addr"); 80 | return 0; 81 | } 82 | memmove(ea, xx.ifr_hwaddr.sa_data, 6); 83 | return 1; 84 | } 85 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | The aoetools are programs that assist in using ATA over Ethernet on 2 | systems with version 2.6 and newer Linux kernels. 3 | 4 | Systems running 2.4 Linux kernels do not need and should not install 5 | the aoetools. The aoe driver for 2.4 kernels is self sufficient. 6 | 7 | Please see the aoetools manpage for a brief list of the tools. 8 | 9 | -------------------------------------------------------------------- 10 | AOE DRIVER COMPATIBILITY 11 | 12 | If you are using udev on your system, the aoe-mkdevs and aoe-mkshelf 13 | should not be used. Just let udev create device nodes for you. If 14 | you need to configure udev, its manpages, in conjunction with the 15 | example in the EtherDrive HOWTO FAQ, should help. 16 | 17 | If you are not using udev, it is important to ensure that the device 18 | nodes in /dev/etherd match the aoe driver. Please see devnodes.txt 19 | for information. 20 | 21 | -------------------------------------------------------------------- 22 | BUILDING THE AOETOOLS 23 | 24 | If you need to configure the software, look at the variables at the 25 | top of the Makefile. The defaults should work for most people. When 26 | using the defaults there's only one step to configure and install the 27 | aoetools software and documentation: 28 | 29 | make install 30 | 31 | You'll need sufficient permissions to install in the default locations 32 | if you haven't overridden them with your own locations. 33 | 34 | The aoe-sancheck tool depends on libpthread. If its header and 35 | library files are not present, the aoetools makefile skips 36 | aoe-sancheck. You can install your Linux distribution's "libpthread" 37 | and "libpthread-devel" packages (They might be called something 38 | slightly different) to help aoe-sancheck to build successfully. 39 | 40 | -------------------------------------------------------------------- 41 | LEGACY TOOLS 42 | 43 | These two are legacy commands for systems without udev. 44 | 45 | aoe-mkdevs create character and block device files 46 | aoe-mkshelf create block device files for one shelf address 47 | 48 | -------------------------------------------------------------------- 49 | RESOURCES 50 | 51 | The aoetools on github 52 | https://github.com/OpenAoE/aoetools 53 | 54 | The aoetools homepage 55 | http://aoetools.sourceforge.net/ 56 | 57 | OpenAoE 58 | http://www.openaoe.org/ -------------------------------------------------------------------------------- /aoe-stat.in: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # aoe-stat - collate and present information about AoE storage 3 | # Copyright 2012, CORAID, Inc., and licensed under GPL v.2. 4 | 5 | set -e 6 | me=`basename $0` 7 | sysd=${sysfs_dir:-/sys} 8 | 9 | # printf "$format" device mac netif state 10 | 11 | # Suse 9.1 Pro doesn't put /sys in /etc/mtab 12 | #test -z "`mount | grep sysfs`" && { 13 | test ! -d "$sysd/block" && { 14 | echo "$me Error: sysfs is not mounted" 1>&2 15 | exit 1 16 | } 17 | 18 | checknode () { 19 | devname="$1" 20 | m_sysfs="$2" 21 | if test -b "@devdir@/$devname"; then 22 | m_node="`ls -l \"@devdir@/$devname\" | awk '{print $6}'`" 23 | test "$m_sysfs" = "$m_node" || { 24 | cat 1>&2 </dev/null | grep -v p` end; do 48 | # maybe ls comes up empty, so we use "end" 49 | test $d = end && continue 50 | 51 | test -r "$d/payload" && payload=yes 52 | done 53 | if test "$payload" = "yes"; then 54 | format="%10s %15s %10s %-5s %-14s\n" 55 | else 56 | format="%10s %15s %6s %-14s\n" 57 | fi 58 | for d in `ls -d $sysd/block/*e[0-9]*\.[0-9]* 2>/dev/null | grep -v p` end; do 59 | test $d = end && continue 60 | 61 | dev=`echo "$d" | sed 's/.*!//'` 62 | if test -r "$d"/dev; then 63 | minor="`awk -F: '{print $2}' \"$d/dev\"`" 64 | checknode "$dev" "$minor" 65 | else 66 | minor="$NA" 67 | fi 68 | sectors=`cat_or_NA "$d"/size` 69 | if test "$sectors" = "$NA"; then 70 | psize="$NA" 71 | else 72 | psize=$(((512000 * $sectors) / (1000 * 1000 * 1000))) 73 | psize=`printf "%04d\n" $psize | sed 's!\(...\)$!.\1!'`GB 74 | fi 75 | netif=`cat_or_NA "$d"/netif` 76 | state=`cat_or_NA "$d"/state` 77 | payload=`cat_or_NA "$d"/payload` 78 | if test "$payload" != "$NA"; then 79 | printf "$format" \ 80 | "$dev" \ 81 | "${psize}" \ 82 | "$netif" \ 83 | "$payload" \ 84 | "$state" 85 | else 86 | printf "$format" \ 87 | "$dev" \ 88 | "${psize}" \ 89 | "$netif" \ 90 | "$state" 91 | fi 92 | done | sort | grep $re 93 | -------------------------------------------------------------------------------- /aoe-mkshelf.8: -------------------------------------------------------------------------------- 1 | .TH aoe-mkshelf 8 2 | .SH NAME 3 | aoe-mkshelf \- create special device files for one shelf address 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-mkshelf {device-dir} {shelf-address} 7 | .B env n_partitions=1 aoe-mkshelf {device-dir} {shelf-address} 8 | .fi 9 | .SH DESCRIPTION 10 | The 11 | .I aoe-mkshelf 12 | command is not needed on systems that have udev installed and 13 | is incompatible with aoe drivers that have the \fIaoe_dyndevs\fP 14 | module parameter set to 1. 15 | .PP 16 | Systems lacking udev and having an aoe driver that uses static minor 17 | device numbers can use \fIaoe-mkshelf\fP to create the block special 18 | files necessary to access the AoE devices with the given shelf 19 | address. 20 | .PP 21 | All aoe drivers prior to \fIaoe6-50\fP use static minor device 22 | numbers. Versions 50 and up use dynamic minor device numbers 23 | when the module parameter aoe_dyndevs=1 is set. 24 | .PP 25 | If you are using static minor device numbers and your aoe driver 26 | supports only one partition per device (whole-disk 27 | partitions), then the device files must match, and you should use the 28 | .I n_partitions 29 | environment variable described below. 30 | .SS Arguments 31 | .TP 32 | \fBdevice-dir\fP 33 | This should be the name of the directory where the block device files 34 | will be created. 35 | .TP 36 | \fBshelf-address\fP 37 | This is the AoE major address, or shelf address, for which to create 38 | device nodes. For example, specifying a shelf address of 1 means that 39 | the e1.* device nodes will be created in \fBdevice-dir\fP. 40 | .SH ENVIRONMENT VARIABLES 41 | If the 42 | .I n_partitions 43 | variable is set in the environment, it will override the default 44 | number of partitions per aoe disk, namely 16. 45 | .SH EXAMPLE 46 | In this example, the root user on a host named 47 | .I nai 48 | creates special files for using the aoe disks in shelf 7. Then he 49 | remembers that the driver doesn't have partition support, so the 50 | command is called again with \fIn_partitions\fP set to 1. 51 | .IP 52 | .EX 53 | .nf 54 | nai:~# aoe-mkshelf /dev/etherd 7 55 | nai:~# ls /dev/etherd/e7.* | wc \-l 56 | 160 57 | nai:~# rm /dev/etherd/e7.* 58 | nai:~# n_partitions=1 aoe-mkshelf /dev/etherd 7 59 | nai:~# ls /dev/etherd/e7.* | wc \-l 60 | 10 61 | nai:~# 62 | .fi 63 | .EE 64 | .SH "SEE ALSO" 65 | .IR aoe-discover (8), 66 | .IR aoe-interfaces (8), 67 | .IR aoe-mkdevs (8), 68 | .IR aoe-stat (8), 69 | .IR aoetools (8), 70 | .IR udev (7). 71 | .SH AUTHOR 72 | Ed L. Cashin (ecashin@coraid.com) 73 | -------------------------------------------------------------------------------- /aoe-mkdevs.8: -------------------------------------------------------------------------------- 1 | .TH aoe-mkdevs 8 2 | .SH NAME 3 | aoe-mkdevs \- create special device files for aoe driver 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-mkdevs {device-dir} 7 | .B env n_partitions=1 aoe-mkdevs {device-dir} 8 | .fi 9 | .SH DESCRIPTION 10 | The 11 | .I aoe-mkdevs 12 | command is deprecated in favor of udev. Systems with udev do not need 13 | to use the \fIaoe-mkdevs\fP or \fIaoe-mkshelf\fP commands, because udev 14 | will create device nodes as needed. 15 | .PP 16 | Systems without udev use \fIaoe-mkdevs\fP to create the character 17 | special files necessary to 18 | control the aoe driver. The \fIaoe-mkdevs\fP command uses 19 | .I aoe-mkshelf 20 | to also create block special files. 21 | .PP 22 | The aoe drivers after version 49 support dynamic minor device numbers 23 | so that a greater number of devices can be supported. The 24 | \fIaoe-mkdevs\fP command is incompatible with dynamic device numbers. 25 | If your system lacks udev, and you are using an aoe driver version 50 26 | or above, use the aoe_dyndevs=0 module option to force the aoe driver 27 | to use static device numbers. 28 | .PP 29 | If you are not using dynamic device numbers, and you built your aoe 30 | driver to support only one partition per device 31 | (whole-disk 32 | partitions), then the device files must match, and you should use the 33 | .I n_partitions 34 | environment variable described below. 35 | .SS Arguments 36 | .TP 37 | \fBdevice-dir\fP 38 | This should be the name of the directory where the special device files 39 | will be created. 40 | .SH ENVIRONMENT VARIABLES 41 | If the 42 | .I n_partitions 43 | variable is set in the environment, it will override the default 44 | number of partitions per aoe disk, namely 16. 45 | .SH EXAMPLE 46 | In this example, the root user on a host named 47 | .I nai 48 | creates special files for using the aoe disks in shelf 7. After 49 | remembering that the driver doesn't have partition support, this 50 | sysadmin gets rid of the mismatching device nodes and calls 51 | \fIaoe-mkdevs\fP again with \fIn_partitions\fP set to 1. 52 | .IP 53 | .EX 54 | .nf 55 | nai:~# rm \-rf /dev/etherd 56 | nai:~# aoe-mkdevs /dev/etherd 57 | nai:~# ls /dev/etherd | wc \-l 58 | 1603 59 | nai:~# rm \-rf /dev/etherd 60 | nai:~# n_partitions=1 aoe-mkdevs /dev/etherd 61 | nai:~# ls /dev/etherd | wc \-l 62 | 103 63 | .fi 64 | .EE 65 | .SH "SEE ALSO" 66 | .IR aoe-discover (8), 67 | .IR aoe-interfaces (8), 68 | .IR aoe-mkshelf (8), 69 | .IR aoe-stat (8), 70 | .IR aoetools (8), 71 | .IR udev (7). 72 | .SH AUTHOR 73 | Ed L. Cashin (ecashin@coraid.com) 74 | -------------------------------------------------------------------------------- /coraid-update: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # usage: coraid-update {update file} {AoE target} 3 | # coraid-update depends upon sysfs mounted on /sys 4 | 5 | # The destination must be, 6 | # 1) an AoE target ready for I/O, and 7 | # 2) not too big to be an update target 8 | # 9 | # Later, when CORAID appliances mark update targets with special ATA 10 | # device identify content or special target content, a prompt should 11 | # be added after the check of the target's size if the identifying 12 | # content is not detected. 13 | # 14 | # The update file must either, 15 | # 1) be an SR tarc file that looks OK to the local tar, or 16 | # 2) any file not ending in ".tarc". 17 | 18 | # size of update LUN in /proc/partitions is 40000 19 | max=70000 20 | 21 | usage="usage: coraid-update {update file} {AoE device}" 22 | if test "$#" != 2; then 23 | echo "$usage" 1>&2 24 | exit 1 25 | fi 26 | update="$1" 27 | ulb="$2" 28 | 29 | # if it's an update target, it should be in `aoe-stat` 30 | aoe-stat | awk -vt="`basename $ulb`" ' 31 | BEGIN{fail=1} 32 | $1==t{fail=0} 33 | END{exit fail}' || { 34 | exec 1>&2 35 | echo "coraid-update Error: \"$ulb\" is not an AoE target" 36 | echo "$usage" 37 | exit 1 38 | } 39 | 40 | # it should have a size no larger than $max in /proc/partitions 41 | t="`echo $ulb | sed 's!^/dev/!!'`" 42 | awk -vt="$t" '$NF==t{print $3}' /proc/partitions | 43 | awk -vhi=$max -vdev="$ulb" ' 44 | BEGIN{ 45 | err = "could not get size of " dev 46 | } { 47 | err = "none" 48 | if ($1 > hi) { 49 | err = dev " is too large to be an update target" 50 | exit 51 | } 52 | } END{ 53 | if (err != "none") { 54 | print "Error coraid-update: " err > "/dev/stderr" 55 | exit 1 56 | } 57 | exit 0 58 | }' || exit 1 59 | 60 | # this test should be removed when it is performed on the appliance 61 | # 62 | # For a 2734080-byte tarc file, an incomplete file of 2727450 bytes passes 63 | # this test, but one of 2727400 does not. So this test isn't fullproof. 64 | # 65 | if test "`echo \"$update\" | grep '\.tarc$'`"; then 66 | tar tf "$update" > /dev/null 2>&1 || { 67 | exec 1>&2 68 | echo "coraid-update Error: \"$update\" does not appear to be a valid tarc file" 69 | exit 1 70 | } 71 | fi 72 | if test ! -r "$update"; then 73 | echo "coraid-update Error: \"$update\" is not readable" 1>&2 74 | exit 1 75 | fi 76 | 77 | # send it over and complain on error 78 | if ! dd if="$update" of="$ulb" 2> /dev/null || ! sync; then 79 | exec 1>&2 80 | echo "coraid-update Error: could not successfully write \"$update\" to \"$ulb\"" 81 | exit 1 82 | fi 83 | -------------------------------------------------------------------------------- /aoecfg.8: -------------------------------------------------------------------------------- 1 | .TH aoecfg 8 2 | .SH NAME 3 | aoecfg \- manipulate AoE configuration strings 4 | .SH SYNOPSIS 5 | .B aoecfg 6 | [\-c \fIcmd\fR] [\-s \fIcfgstr\fR] [\-t \fItimeout\fR] [\fIshelf slot\fR] [\fInetif\fR] 7 | .fi 8 | .SH DESCRIPTION 9 | .IR Aoecfg (8) 10 | sends AoE configuration commands that control the retrivial, conditional 11 | or unconditional setting of AoE configuration strings. Since configuration 12 | happens before the MAC address of the target is known, the packet is 13 | broadcast. AoE targets with a matching shelf and slot respond. Since 14 | the default shelf and slot are the wildcard values 0xffff and 0xff, 15 | with no arguments 16 | .IR aoecfg (8) 17 | will return configuration strings from all targets visible 18 | on the default interface, 19 | .IR eth0 . 20 | .SH OPTIONS 21 | .TP 8 22 | .BI \-c " cmd" 23 | specify the AoE configuration command. The default is 24 | .IR read . 25 | The available commands are 26 | .HP 8 27 | .B read 28 | Read the server config string without performing any test and 29 | respond. 30 | .HP 8 31 | .B test 32 | Respond only if the specified string exactly matches the server 33 | configuration string. 34 | .HP 8 35 | .B prefix 36 | Respond only if the specified string is a prefix of the server 37 | configuration string. 38 | .HP 8 39 | .B set 40 | If the current server config string is empty, set the server config 41 | string to the argument string and respond. If the current server 42 | config string is not empty, return a response with Flags bit E set 43 | and Error set to 4. 44 | .HP 8 45 | .B fset 46 | Force set the server config string to the argument string and respond. 47 | .TP 48 | .BI \-s " cfgstr" 49 | specify the config string. 50 | .TP 51 | .BI \-t " timeout" 52 | specify the timeout in seconds. The default is no timeout. If neither the shelf 53 | nor the slot are specified, 54 | .IR aoecfg (8) 55 | will exit after the first result. Otherwise, 56 | .IR aoecfg (8) 57 | will exit only after the timeout has expired since it does not know 58 | how many responses to expect. 59 | .TP 60 | .B shelf slot 61 | specify the shelf and slot used in the query. If unspecified, they 62 | default to broadcast. 63 | .TP 64 | .B netif 65 | specify the network interface. The default is 66 | .IR eth0 . 67 | .SH "SEE ALSO" 68 | .IR aoe-discover (8), 69 | .IR aoe-interfaces (8), 70 | .IR aoe-mkdevs (8), 71 | .IR aoe-mkshelf (8), 72 | .IR aoe-stat (8), 73 | .IR aoeping (8), 74 | \fIAoE (ATA over Ethernet)\fP: http://support.coraid.com/documents/AoEr10.txt, 75 | \fIATA specification\fP 76 | .SH AUTHOR 77 | Erik Quanstrom (quanstro@coraid.com) 78 | -------------------------------------------------------------------------------- /aoe-interfaces.8: -------------------------------------------------------------------------------- 1 | .TH aoe-interfaces 8 2 | .SH NAME 3 | aoe-interfaces \- restrict aoe driver to specified network interfaces 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-interfaces [dev1] [dev2 ...] 7 | .B aoe-interfaces -c 8 | .fi 9 | .SH DESCRIPTION 10 | The 11 | .I aoe-interfaces 12 | command tells the aoe driver to ignore ATA over Ethernet (AoE) traffic 13 | on all but the specified network interfaces. It is analogous to the 14 | \fIaoe_iflist\fP module load option. 15 | .PP 16 | If neither the \fIaoe_iflist\fP module load option nor the 17 | \fIaoe-interfaces\fP command are used, the aoe driver will use any 18 | network interface for AoE traffic. Using \fIaoe-interfaces\fP to 19 | limit AoE to only trusted networks prevents the case where a rogue AoE 20 | target appears on a public network, diverting data from the legitimate 21 | AoE target. Such an imposter target effectively corrupts the data on 22 | the legitimate target. 23 | .PP 24 | If the aoe driver is a module, then calling 25 | .I aoe-interfaces 26 | without arguments will display the current interfaces list. If it 27 | hasn't been set then the output will be blank. 28 | .PP 29 | It's good to run the 30 | .I aoe-discover 31 | command after setting the AoE interfaces list. 32 | .SH OPTIONS 33 | .TP 34 | \fB-c\fP 35 | The \fB-c\fP flag will clear the interface access list, permitting any interface to be used. 36 | .SH EXAMPLE 37 | In this example, the root user on a host named 38 | .I nai 39 | loads the aoe module with only eth0 allowable for AoE traffic. After 40 | remembering that shelf 7 is on eth3, this 41 | sysadmin uses 42 | .I aoe-interfaces 43 | to add eth3 to the list of allowable network interfaces and then 44 | calls 45 | .I aoe-discover 46 | to ask the aoe driver to look for new AoE devices. 47 | .IP 48 | .EX 49 | .nf 50 | nai:~# modprobe aoe aoe_iflist="eth0" 51 | nai:~# aoe-stat 52 | e10.9 eth0 up 53 | nai:~# aoe-interfaces eth0 eth3 54 | nai:~# aoe-discover 55 | nai:~# aoe-stat 56 | e7.0 eth3 up 57 | e7.1 eth3 up 58 | e7.2 eth3 up 59 | e7.3 eth3 up 60 | e7.4 eth3 up 61 | e7.5 eth3 up 62 | e7.6 eth3 up 63 | e7.7 eth3 up 64 | e7.8 eth3 up 65 | e7.9 eth3 up 66 | e10.9 eth0 up 67 | nai:~# aoe-interfaces 68 | eth0 eth3 69 | .fi 70 | .EE 71 | .SH "SEE ALSO" 72 | .IR aoe-discover (8), 73 | .IR aoe-stat (8), 74 | .IR aoetools (8). 75 | .SH AUTHOR 76 | Ed L. Cashin (ecashin@coraid.com) 77 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | # You can edit this file or override these variables on 4 | # the commandline. For example, "make install MANDIR=/tmp/man" 5 | # would use defaults for all variables except ${MANDIR}. 6 | 7 | 8 | # You can set this to something like /opt/aoetools-x 9 | # if you want to install everything in one place. 10 | # 11 | # Note that even with ${PREFIX} set, the devices in 12 | # /dev/etherd will be used unless you override ${DEVDIR}. 13 | PREFIX = 14 | 15 | # Your aoe-driver device files should be in ${DEVDIR}. 16 | DEVDIR = /dev/etherd 17 | 18 | # The programs will be installed in ${SBINDIR}. 19 | SBINDIR = ${PREFIX}/usr/sbin 20 | MANDIR = ${PREFIX}/usr/share/man 21 | 22 | # NPERSHELF is the number of slot addresses per shelf address. 23 | # This number must match the same setting in the aoe driver. 24 | # 25 | # Older aoe drivers have NPERSHELF set to 10, and newer ones 26 | # use 16. 27 | # 28 | # You can see the setting in your driver like this in the driver 29 | # source directory. (Change into the "linux" directory if you're 30 | # using the standalone driver from CORAID.) 31 | # 32 | # grep 'NPERSHELF.*=' drivers/block/aoe/aoe.h 33 | # 34 | NPERSHELF=16 35 | 36 | # end of user-configurable variables 37 | 38 | 39 | # these scripts are created from the *.in files 40 | CONF_SCRIPTS = aoe-discover aoe-interfaces aoe-mkshelf aoe-revalidate aoe-flush aoe-stat 41 | PROGS = aoeping aoecfg aoe-sancheck 42 | COMMANDS := ${CONF_SCRIPTS} aoe-mkdevs aoe-version coraid-update ${PROGS} 43 | CFLAGS = -Wall -O -g 44 | SANCHECKLIBS = -lpthread 45 | 46 | AOE_PING_OBJ = aoeping.o linux.o 47 | AOE_CFG_OBJ = aoecfg.o linux.o 48 | SANCHECK_OBJ = aoe-sancheck.o 49 | 50 | all : configure ${PROGS} 51 | @true 52 | 53 | configure : 54 | @for f in ${CONF_SCRIPTS}; do \ 55 | sh -xc "sed -e 's!@devdir@!${DEVDIR}!g' -e 's!@npershelf@!${NPERSHELF}!g' $$f.in > $$f" || break; \ 56 | done 57 | 58 | # DESTDIR was put in for Rob Holland to make gentoo packaging easier 59 | install : all 60 | mkdir -p ${DESTDIR}${SBINDIR} 61 | mkdir -p ${DESTDIR}${MANDIR}/man8 62 | @for f in ${COMMANDS}; do \ 63 | sh -xc "install -m 700 $$f ${DESTDIR}${SBINDIR}/$$f" || break; \ 64 | sh -xc "install -m 664 $$f.8 ${DESTDIR}${MANDIR}/man8/$$f.8" || break; \ 65 | done 66 | 67 | clean : 68 | rm -f ${CONF_SCRIPTS} ${AOE_PING_OBJ} ${AOE_CFG_OBJ} ${SANCHECK_OBJ} ${PROGS} 69 | 70 | aoeping : ${AOE_PING_OBJ} 71 | ${CC} ${CFLAGS} -o $@ ${AOE_PING_OBJ} 72 | aoeping.o : aoeping.c dat.h fns.h 73 | ${CC} ${CFLAGS} -o $@ -c $< 74 | linux.o : linux.c config.h 75 | ${CC} ${CFLAGS} -o $@ -c $< 76 | aoecfg: ${AOE_CFG_OBJ} 77 | ${CC} ${CFLAGS} -o $@ ${AOE_CFG_OBJ} 78 | aoecfg.o : aoecfg.c dat.h fns.h 79 | ${CC} ${CFLAGS} -o $@ -c $< 80 | aoe-sancheck : ${SANCHECK_OBJ} 81 | -$(CC) $(CFLAGS) -o $@ ${SANCHECK_OBJ} $(SANCHECKLIBS) 82 | aoe-sancheck.o : aoe-sancheck.c 83 | -$(CC) $(CFLAGS) -o $@ -c $< 84 | 85 | -------------------------------------------------------------------------------- /aoe-sancheck.8: -------------------------------------------------------------------------------- 1 | .TH aoe-sancheck 8 2 | .SH NAME 3 | aoe-sancheck \- verify storage network capabilities 4 | .SH SYNOPSIS 5 | .nf 6 | .B aoe-sancheck [\-v] 7 | .fi 8 | .SH DESCRIPTION 9 | The 10 | .I aoe-sancheck 11 | command collects information about the local interfaces and probes the network for ATA over Ethernet devices, validating the paths for each device. It does not use the aoe kernel module but rather the bpf interface to evaluate the network. As such, the aoe module does not need to be loaded to perform the test. 12 | .PP 13 | The output of the command is divided into two sections: information about the local interfaces followed by a list of detected AoE devices. The first section displays the local interfaces, if the interface is up or down, its configured MTU, and the PCI ID for the interface. 14 | .PP 15 | The second section lists detected AoE devices, one per line, with the following information: 16 | .TP 17 | .BI Device 18 | The device name of the form 19 | .I eX.Y 20 | where 21 | .I X 22 | is the AoE device shelf address, and 23 | .I Y 24 | is the AoE device slot address. 25 | .TP 26 | .BI Macs 27 | The number of mac addresses detected for this device. 28 | .TP 29 | .BI Payload 30 | The number of bytes of data the device can handle in a single AoE request. This number does not represent the total frame size as it does not include bytes from ethernet or AoE headers. 31 | .TP 32 | .BI "Local Interfaces" 33 | The list of local interfaces from which the device is visible. 34 | .SS Options 35 | .TP 36 | \fB\-v\fP 37 | Prints out additional raw information. 38 | .SH DIAGNOSIS 39 | For each device, 40 | .I aoe-sancheck 41 | may print out additional lines of suggestions or warnings. The following checks are made: 42 | .TP 43 | .BI "The MTU of the local interfaces is set high enough to handle the AoE device's reported payload. " 44 | Depending on the host NIC's capabilities and storage network switch's capabilities, best performance may or may not be with local interface MTU set higher than a device's payload size. 45 | .TP 46 | .BI "The number of local interfaces matches the number of interfaces on the device. " 47 | Best performance comes from having a host and device with comparable bandwidth. \fIAoe-sancheck\fP simply counts the number of interfaces involved and does not figure link bandwidth in its comparison. 48 | .TP 49 | .BI "All local interfaces for an AoE device have the same MTU." 50 | If one interface for a device has a smaller MTU than the others, the AoE driver must use the smaller payload size for all interfaces. 51 | .TP 52 | .BI "Each path to the device is capable of the configured payload size." 53 | This check detects the situation where a local interface is configured for jumbo frames and the AoE device is capable of jumbo frames, but some aspect of the network is incapable of passing frames that size, for example, a misconfigured switch. \fIAoe-sancheck\fP reports the maximum payload size the path is capable of if less than the configured payload size. 54 | .SH BUGS 55 | The program may sometimes display inconsistent results between runs showing that a path is capable of a smaller frame size than it actually is. If you see this behavior, please email one of the authors with your verbose output. 56 | .PP 57 | The program probes only the first 32 ethernet interfaces found in the system. 58 | .SH "SEE ALSO" 59 | .IR aoeping (8), 60 | .IR aoetools (8) 61 | .SH AUTHORS 62 | Justin Sanders (justin@coraid.com), 63 | Sam Hopkins (sah@coraid.com) 64 | -------------------------------------------------------------------------------- /aoe-stat.8: -------------------------------------------------------------------------------- 1 | .TH aoe-stat 8 2 | .SH NAME 3 | aoe-stat \- print aoe device status report 4 | .SH SYNOPSIS 5 | .nf 6 | .B modprobe aoe 7 | .B aoe-stat 8 | .B env sysfs_dir=/sys aoe-stat 9 | .fi 10 | .SH DESCRIPTION 11 | The 12 | .I aoe-stat 13 | script collects information on ATA over Ethernet devices from sysfs. 14 | .PP 15 | For each AoE device the kernel has discovered, there is one row in the 16 | script's output. Each row has 17 | the following columns. 18 | .TP 19 | .BI devicename 20 | The device name is of the form 21 | .I eX.Y, 22 | with 23 | .I X 24 | being the AoE device shelf address, and 25 | .I Y 26 | being the AoE slot address. 27 | .TP 28 | .BI size 29 | The size of the AoE device is in gigabytes (billions of bytes). 30 | .TP 31 | .BI ifname 32 | The network interface name is printed in the third column. 33 | .TP 34 | .BI payload 35 | The number of bytes read from or written to the storage target in 36 | each AoE packet appears in the fourth column, unless the aoe driver 37 | does not export this information. 38 | .TP 39 | .BI status 40 | The device status is in the last column. Possible values 41 | are \fI up\fR, \fI down\fR, 42 | and \fI down,closewait\fR. The "up" status means the aoe driver 43 | considers this device ready 44 | for I/O. The "down" status means the opposite. The "down,closewait" 45 | status means that some software still has the device open, and when 46 | this straggler closes the device, it will enter the "down" state. 47 | .SH UNAVAILABLE TARGETS 48 | If a discovered AoE target will not respond to I/O commands, some 49 | of the information needed to allow Linux to use the device is not 50 | available. The 51 | .I aoe-stat 52 | command shows the missing information as "(NA)" fields. 53 | .PP 54 | It is normal for "(NA)" fields to appear during the brief 55 | time between the time that an AoE target is detected and the 56 | time the Linux kernel finishes reading its partition table. 57 | .SH ENVIRONMENT VARIABLES 58 | If the 59 | .I sysfs_dir 60 | variable is set in the environment, it will override the default 61 | location where 62 | .I aoe-stat 63 | will look for 64 | sysfs, namely \fI /sys\fR. 65 | .SH WARNINGS 66 | If the minor device number of a device node does not match that of its 67 | namesake, \fIaoe-stat\fP will print a warning as shown below. 68 | .IP 69 | .EX 70 | .nf 71 | nai:~# aoe-stat 72 | e0.3 0.104GB eth0 up 73 | e0.4 4398.046GB eth0 up 74 | e20.0 1000.215GB eth0 up 75 | e42.0 2000.431GB eth0 up 76 | aoe-stat Warning: device node /dev/etherd/e45.1 has wrong minor device number 77 | e45.1 1152.874GB eth0 up 78 | .fi 79 | .EE 80 | .PP 81 | Using such a device node is dangerous, because its name doesn't match 82 | the actual device that you would be reading from and writing to. Such 83 | a broken device node should be removed. Device nodes are created by 84 | \fIudev\fP or (on systems without \fIudev\fP) by \fIaoe-mkdevs\fP. 85 | .SH EXAMPLE 86 | In this example, the root user on a host named 87 | .I nai 88 | loads the aoe driver module and then prints a list of all the 89 | available aoe devices. Then he remembers to bring up the storage 90 | network interfaces, does an AoE discovery, and prints the list again. 91 | This time the list shows all the devices in shelf seven. 92 | .IP 93 | .EX 94 | .nf 95 | nai:~# modprobe aoe 96 | nai:~# aoe-stat 97 | nai:~# ifconfig eth3 up 98 | nai:~# aoe-discover 99 | nai:~# aoe-stat 100 | e0.0 10995.116GB eth3 up 101 | e0.1 10995.116GB eth3 up 102 | e0.2 10995.116GB eth3 up 103 | e1.0 1152.874GB eth3 up 104 | e7.0 370.566GB eth3 up 105 | nai:~# 106 | .fi 107 | .EE 108 | .SH "SEE ALSO" 109 | .IR aoe-discover (8), 110 | .IR aoe-interfaces (8), 111 | .IR aoe-mkdevs (8), 112 | .IR aoe-mkshelf (8), 113 | .IR aoetools (8), 114 | .IR udev (7). 115 | .SH AUTHOR 116 | Ed L. Cashin (ecashin@coraid.com) 117 | -------------------------------------------------------------------------------- /aoecfg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * aoecfgstr.c - fiddle aoe configuration strings. 3 | * Copyright 2009, Erik Quanstrom, CORAID, Inc., Licenced under GPL v2 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "dat.h" 17 | #include "fns.h" 18 | 19 | int sfd; 20 | uchar mac[6]; 21 | int timeout; 22 | u16 shelf = 0xffff; 23 | uchar slot = 0xff; 24 | char *net = "eth0"; 25 | char *cfgstr; 26 | int cfgstrlen; 27 | 28 | char *errtab[7] = { 29 | "*GOK*", 30 | "*badcmd*", 31 | "*badarg*", 32 | "*baddev*", 33 | "*badcfg*", 34 | "*badvers*", 35 | "*GOK*", 36 | }; 37 | 38 | void 39 | resp(Conf *c) 40 | { 41 | Aoehdr *h; 42 | char *s; 43 | int l; 44 | 45 | h = (Aoehdr*) c; 46 | if (h->flags & Error) { 47 | s = errtab[h->error & 7]; 48 | l = strlen(s); 49 | } else { 50 | s = (char*) c->data; 51 | l = ntohs(c->len); 52 | } 53 | if (shelf != 0xffff && slot != 0xff) 54 | printf("%.*s\n", l, s); 55 | else 56 | printf("%d.%d\t%.*s\n", ntohs(h->maj), h->min, l, s); 57 | } 58 | 59 | int 60 | readto(int fd, void *buf, int size) 61 | { 62 | fd_set rfd; 63 | struct timeval tv; 64 | static int to; 65 | 66 | if (timeout == 0) 67 | goto f1; 68 | if (to == 0) 69 | to = time(0) + timeout; 70 | FD_ZERO(&rfd); 71 | FD_SET(fd, &rfd); 72 | 73 | tv.tv_sec = to - time(0); 74 | tv.tv_usec = 0; 75 | 76 | switch (select(fd+1, &rfd, 0, 0, &tv)) { 77 | case -1: 78 | perror("select"); 79 | exit(1); 80 | case 0: 81 | exit(0); 82 | } 83 | f1: 84 | return read(fd, buf, size); 85 | } 86 | 87 | u32 88 | aoe_tag(void) 89 | { 90 | u32 n; 91 | struct timeval t = { 0, 0 }; 92 | 93 | /* Tag should be just enough to avoid conflicts with other 94 | * aoeping and aoecfg processes, and should set high bit 95 | * to avoid conflicting with in-kernel AoE. 96 | */ 97 | if (gettimeofday(&t, NULL)) { 98 | perror("gettimeofday"); 99 | exit(1); 100 | } 101 | n = t.tv_usec | 1UL << 31; 102 | return htonl(n); 103 | } 104 | 105 | void 106 | cfgquery(int cmd, int shelf, int slot) 107 | { 108 | int n; 109 | Aoehdr *h; 110 | Conf *c; 111 | uchar buf[1024 + sizeof *h]; 112 | u32 tag; 113 | 114 | c = (Conf*) buf; 115 | h = (Aoehdr*) c; 116 | memset(h, 0, sizeof *h); 117 | memset(h->dst, 0xff, sizeof h->dst); 118 | memmove(h->src, mac, sizeof h->src); 119 | 120 | h->type = htons(AOE_ETH_PROTO); 121 | h->flags = AoEver << 4; 122 | h->maj = htons(shelf); 123 | h->min = slot; 124 | h->cmd = Config; 125 | tag = aoe_tag(); 126 | memmove(h->tag, &tag, sizeof h->tag); 127 | c->bufcnt = 0; 128 | c->firmware = 0; 129 | c->scnt = 0; 130 | c->vercmd = cmd; 131 | memmove(c->data, cfgstr, cfgstrlen); 132 | c->len = htons(cfgstrlen); 133 | if (write(sfd, c, sizeof *c) == -1) { 134 | perror("send config query"); 135 | exit(1); 136 | } 137 | for (;;) { 138 | n = readto(sfd, buf, sizeof buf); 139 | if (n < 0) { 140 | perror("read network"); 141 | exit(1); 142 | } 143 | if (n < 60) 144 | continue; 145 | h = (Aoehdr *) buf; 146 | if (ntohs(h->type) != AOE_ETH_PROTO) 147 | continue; 148 | if (ntohs(h->maj) == 0xffff || h->min == 0xff) 149 | continue; 150 | if (shelf != 0xffff && ntohs(h->maj) != shelf) 151 | continue; 152 | if (slot != 0xff && h->min != slot) 153 | continue; 154 | if (memcmp(h->tag, &tag, sizeof h->tag)) 155 | continue; 156 | resp((Conf*) buf); 157 | if (shelf != 0xffff && slot != 0xff) 158 | break; 159 | } 160 | } 161 | 162 | void 163 | usage(void) 164 | { 165 | fputs("usage: aoecfg " 166 | "[-c cmd] [-s cfgstr] [-t timeout] " 167 | "[shelf slot] [net]\n", stderr); 168 | exit(1); 169 | } 170 | 171 | typedef struct{ 172 | char *s; 173 | int cmd; 174 | } Tab; 175 | 176 | Tab tab[] = { 177 | { "read", Qread, }, 178 | { "test", Qtest, }, 179 | { "prefix", Qprefix, }, 180 | { "set", Qset, }, 181 | { "fset", Qfset, }, 182 | }; 183 | 184 | int 185 | xlatecmd(char *s) 186 | { 187 | int i; 188 | 189 | for (i = 0; i < nelem(tab); i++) 190 | if (strcmp(tab[i].s, s) == 0) 191 | return tab[i].cmd; 192 | usage(); 193 | return -1; // whine whine whine 194 | } 195 | 196 | int 197 | main(int argc, char *argv[]) 198 | { 199 | int c, cmd; 200 | 201 | cmd = Qread; 202 | while ((c = getopt(argc, argv, "s:c:t:v")) != -1) { 203 | switch (c) { 204 | case 'c': 205 | cmd = xlatecmd(optarg); 206 | break; 207 | case 's': 208 | cfgstr = optarg; 209 | cfgstrlen = strlen(cfgstr); 210 | break; 211 | case 't': 212 | timeout = atoi(optarg); 213 | break; 214 | default: 215 | usage(); 216 | } 217 | } 218 | 219 | c = argc - optind; 220 | argv += optind; 221 | if (c < 2) 222 | goto f1; 223 | if (c != 3 && c != 2) 224 | usage(); 225 | shelf = strtoul(*argv++, 0, 0); 226 | slot = strtoul(*argv++, 0, 0); 227 | f1: 228 | if (*argv) { 229 | net = *argv; 230 | if (isdigit((int) *net)) { 231 | fprintf(stderr, 232 | "aoecfg Error: \"%s\" %s\n", net, 233 | "is not a valid network interface"); 234 | usage(); 235 | } 236 | } 237 | sfd = dial(net); 238 | if (getea(sfd, net, mac) == 0) 239 | exit(1); 240 | cfgquery(cmd, shelf, slot); 241 | return 0; 242 | } 243 | -------------------------------------------------------------------------------- /aoeping.8: -------------------------------------------------------------------------------- 1 | .TH aoeping 8 2 | .SH NAME 3 | aoeping \- simple communication with AoE device 4 | .SH SYNOPSIS 5 | .B aoeping [options] {shelf} {slot} {netif} 6 | .fi 7 | .SH DESCRIPTION 8 | The 9 | .IR aoeping (8) 10 | program performs simple one or two-round-trip communication with an 11 | ATA over Ethernet (AoE) device. It creates and receives AoE packets 12 | directly, using raw network sockets. 13 | .PP 14 | Running 15 | .IR aoeping (8) 16 | without command line arguments will result in a 17 | short usage summary being displayed. 18 | .PP 19 | The 20 | .IR aoeping (8) 21 | program will wait forever if it doesn't receive 22 | an expected response. The caller should use a time out to catch 23 | this situation. 24 | .SS Arguments 25 | .TP 26 | \fBshelf\fP 27 | This should be the shelf address (major AoE address) of the AoE device 28 | to communicate with. 29 | .TP 30 | \fBslot\fP 31 | This should be the slot address (minor AoE address) of the AoE device 32 | to communicate with. 33 | .TP 34 | \fBnetif\fP 35 | The name of the ethernet network interface to use for AoE 36 | communications, e.g., eth1. 37 | .SS Options 38 | .TP 39 | \fB-i\fP 40 | Issue an ATA "identify device" command after receiving the AoE 41 | device's Config 42 | Query response. The "ident" response will be printed on standard 43 | output as a hexadecimal dump. 44 | .TP 45 | \fB-I\fP 46 | Issue an ATA "identify device" command after receiving the AoE 47 | device's Config 48 | Query response. The "ident" response will be pretty-printed on standard 49 | output as selected human-readable fields. 50 | .TP 51 | \fB-v\fP 52 | Turn on 53 | more copious output, including a hexadecimal dump of the Config Query 54 | response from the AoE device (see AoE spec at URL below). 55 | .TP 56 | \fB-s\fP 57 | This option takes an argument. The 58 | argument is a decimal integer that specifies the number of seconds 59 | that 60 | .IR aoeping (8) 61 | will wait for a response before timing out and 62 | exiting with a non-zero status. 63 | .TP 64 | \fB-S\fP 65 | This option takes an argument. The 66 | argument is the name of a SMART command to send to the disk. The 67 | SMART commands in the list below are supported. If the command 68 | requires data 69 | transfer, one sector (512 bytes) of data is always the amount 70 | transferred. If the command takes a parameter (for the Low LBA 71 | register), then the name of the SMART command is immediately followed 72 | by a colon and then a number, the value of the parameter, e.g., "\-S 73 | read_log:1". 74 | .IP 75 | read_data 76 | offline_immediate 77 | read_log 78 | write_log 79 | enable 80 | disable 81 | return_status 82 | 83 | For \fBwrite_log\fP, 84 | .IR aoeping (8) 85 | reads from 86 | standard input the one sector of data to be 87 | written to the specified log. 88 | 89 | If the AoE device does not support SMART commands or if the command is 90 | aborted, an error message 91 | is printed to standard error and 92 | .IR aoeping (8) 93 | exits with a non-zero status. A command may be aborted if SMART is 94 | disabled on the device. 95 | 96 | The 97 | .IR aoeping (8) 98 | command just sends and receives SMART commands, without 99 | interpreting them. See the ATA specification for more information on 100 | using SMART. 101 | .LP 102 | .TP 103 | \fB-t\fP 104 | (This is an advanced feature.) This option has an argument. The 105 | argument is a decimal integer that is used as the initial tag, with 106 | the highest bit set, as 107 | the 108 | first tag in ATA commands. Tags for subsequent ATA commands will be 109 | incremented by one. 110 | .TP 111 | \fB-h\fP 112 | Show a usage summary. 113 | .SH EXAMPLE 114 | In this example, the root user 115 | uses 116 | .IR aoeping (8) 117 | to check for the presence of aoe device e10.9 on 118 | network interface eth0. 119 | .IP 120 | .EX 121 | .nf 122 | bash# aoeping \-v 10 9 eth0 | head 123 | tag: 80000000 124 | eth: eth0 125 | shelf: 10 126 | slot: 9 127 | config query response: 128 | 00 0d 87 aa c9 00 00 10 04 00 11 1f 88 a2 18 00 129 | 00 0a 09 01 00 00 00 00 00 03 30 08 00 10 00 04 130 | 66 6f 6f 0a 00 ff ff ff ff ff ff ff ff ff ff ff 131 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 132 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 133 | .fi 134 | .EE 135 | .LP 136 | The next example shows root making sure the disk on the e10.9 is still 137 | responsive by issuing an ATA device identify command with a 20-second 138 | timeout. 139 | .IP 140 | .EX 141 | .nf 142 | bash# aoeping \-i \-s 20 \\ 143 | 10 9 eth0 > /dev/null \\ 144 | && echo ok 145 | ok 146 | .fi 147 | .EE 148 | .LP 149 | The next example uses SMART to determine whether the disk on e10.9 150 | thinks it 151 | has exceeded its error threshold. The ATA spec says that the LBA Mid 152 | register will be 0x4f when the disk has not exceeded its error 153 | threshold. 154 | .IP 155 | .EX 156 | .nf 157 | bash# aoeping \-S return_status \\ 158 | 10 9 eth0 | grep 'LBA Mid: 0x4f' \\ 159 | > /dev/null \\ 160 | && echo ok 161 | ok 162 | .fi 163 | .EE 164 | .LP 165 | Note that in a script, it would be prudent to specify and handle a 166 | timeout. Also, a good script would make sure the 167 | \fBStatus\fP register does not have the error bit (bit zero) or the 168 | device fault bit (bit 5) set. 169 | .SH "SEE ALSO" 170 | .IR aoe-discover (8), 171 | .IR aoe-interfaces (8), 172 | .IR aoe-mkdevs (8), 173 | .IR aoe-mkshelf (8), 174 | .IR aoe-stat (8), 175 | 176 | \fIAoE (ATA over Ethernet)\fP: http://support.coraid.com/documents/AoEr10.txt, 177 | 178 | \fIATA specification\fP 179 | .SH AUTHOR 180 | Ed L. Cashin (ecashin@coraid.com) 181 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2021-05-21 Christoph Biedl 2 | document and raise the maximum number of aoe-sancheck interfaces 3 | 4 | 2018-01-16 Sergio Prado 5 | make scripts more portable by using /bin/sh for shebang 6 | 7 | 2013-08-07 Ed Cashin 8 | support debugfs-exported debug info in sos-linux 9 | release 36 10 | 11 | 2013-07-10 Ed Cashin 12 | add pkg subdirectory for distro-specific packaging files 13 | 14 | 2012-09-20 Ed Cashin 15 | only use one of the sysfs version files in aoe-version 16 | release 35 17 | 18 | 2012-06-27 Ed Cashin 19 | restore payload field in aoe-stat output 20 | release 34 21 | 22 | 2012-01-24 Ed Cashin 23 | handle missing sysfs files in aoe-stat 24 | update docs for 3.x kernels 25 | remove "function" keyword in aoe-stat for Ubuntu 26 | release 33 27 | 28 | 2010-08-18 Justin Sanders 29 | aoe-sancheck fix: zero out every interface 30 | release 32 31 | 32 | 2010-08-18 Justin Sanders 33 | aoe-sancheck tool diagnoses MTU and other network issues 34 | release 31 35 | 36 | 2009-03-03 Ed Cashin 37 | aoe-version modinfo workaround: cd to a directory without aoe 38 | release 30 39 | 40 | 2008-12-09 Ed Cashin 41 | mention that aoeping uses raw sockets in manpage 42 | use absolute path to aoe.ko when ./aoe is readable 43 | release 29 44 | 45 | 2008-11-11 Ed Cashin 46 | remove "function" reserved word from aoe-flush (for dash shell) 47 | release 28 48 | 49 | 2008-08-01 Ed Cashin 50 | use ".txt" extension for output file of sos-linux 51 | 52 | 2008-06-27 Ed Cashin 53 | aoeping: recognize errors in SMART command response 54 | aoe-stat manpage improvements 55 | release 27 56 | 57 | 2008-05-14 "Ed L. Cashin" 58 | add sos-linux tool for collecting localhost information 59 | release 26 60 | 61 | 2008-04-11 "Ed L. Cashin" 62 | create coraid-update for uploading update file to an update target 63 | create coraid-update manpage 64 | release 25 65 | 66 | 2008-03-25 "Ed L. Cashin" 67 | clean up aoecfg object files in "clean" target 68 | 69 | 2008-02-22 "Ed L. Cashin" 70 | make aoeping and aoecfg more conforming to AoE protocol 71 | release 24 72 | 73 | 2008-01-09 "Ed L. Cashin" 74 | release 23 75 | 76 | 2008-01-09 Sam Hopkins 77 | support new payload size information from aoe driver 78 | 79 | 2008-01-08 "Ed L. Cashin" 80 | handle aoe-flush without arguments correctly 81 | 82 | 2007-12-19 "Ed L. Cashin" 83 | fix aoecfg manpage typo (-s for string) 84 | 85 | 2007-12-10 "Ed L. Cashin" 86 | aoe-flush: support flushing specific devices 87 | release 22 88 | 89 | 2007-10-29 "Ed L. Cashin" 90 | aoe-interfaces should complain about non network interfaces 91 | aoe-interfaces should accept quoted list of interfaces 92 | aoe-interfaces clearing and setting are exclusive actions 93 | release 21 94 | 95 | 2007-10-12 "Ed L. Cashin" 96 | add Erik Quanstrom's aoecfg program 97 | signal error when specified network interface starts with digit 98 | use a tag in the AoE header 99 | do not print shelf and slot when user specified both 100 | have aoeping use a tag for the first packet 101 | add pretty printing of ATA device identify fields 102 | based on input from Joshua Nicholas 103 | release 20 104 | 105 | 2007-08-27 "Ed L. Cashin" 106 | add copyright information 107 | support kernel.org aoe driver in aoe-version 108 | add aoetools manpage 109 | release 19 110 | 111 | 2007-08-08 "Ed L. Cashin" 112 | distinguish between missing device nodes and wrong ones 113 | release 18 114 | 115 | 2007-07-26 "Ed L. Cashin" 116 | aoe-mkdevs and aoe-mkshelf are for systems without udev 117 | aoe-stat warns when device node has wrong minor number 118 | new script, aoe-version, shows installed and running sfw 119 | release 17 120 | 121 | 2007-07-17 "Ed L. Cashin" 122 | check for char devices specifically before using them 123 | 124 | 2007-06-01 "Ed L. Cashin" 125 | workaround dash POSIX math bug 126 | release 16 127 | 128 | 2007-03-20 "Ed L. Cashin" 129 | add quoting to aoe-flush 130 | release 15 131 | 132 | 2007-02-26 Marcus Rueckert 133 | create the same directories we install to 134 | 135 | 2007-02-06 Sam Hopkins 136 | add support for -c flag to aoe-interfaces 137 | add support for -a flag to aoe-flush 138 | update manpages for aoe-interfaces, aoe-flush 139 | release 14 140 | 141 | 2006-12-21 Sam Hopkins 142 | support aoe devices without "etherd" prefix in name 143 | create new character device nodes 144 | release 13 145 | 146 | 2006-10-30 Sam Hopkins 147 | formatting cleanup of man pages 148 | cleanup of scripts, adding error checking 149 | add aoe-flush command 150 | release 12 151 | 152 | 2006-10-13 David Martinez Moreno 153 | aoe-stat: POSIX shell math can't count as high as bash 154 | 155 | 2006-09-07 Anthony Wright 156 | use POSIX shell math instead of relying on dc or bc 157 | release 11 158 | 159 | 2006-05-25 "Ed L. Cashin" 160 | update README: aoetools are for 2.6 systems 161 | release 10 162 | 163 | 2006-01-18 "Ed L. Cashin" 164 | aoe-revalidate: notice error in writing to revalidate device 165 | release 9 166 | 167 | 2005-11-09 Sam Hopkins 168 | add aoe-revalidate 169 | document driver compatibility 170 | release 8 171 | 172 | 2005-08-18 "Ed L. Cashin" 173 | format sub-gigabyte device sizes correctly 174 | release 7 175 | 176 | 2005-08-17 "Ed L. Cashin" 177 | make aoe-stat show device size 178 | release 6 179 | 180 | 2005-07-13 "Ed L. Cashin" 181 | make number of slots per shelf configurable 182 | Rob Holland : install using PREFIX 183 | "make install" builds aoeping 184 | avoid gcc 4 warnings by specifying uchar in params 185 | release 5 186 | 187 | 2005-05-17 "Ed L. Cashin" 188 | fix typo in Makefile preventing aoeping installation: s/PROG/PROGS/ 189 | add TODO file 190 | release 4 191 | 192 | 2005-04-14 "Ed L. Cashin" 193 | add very basic SMART support to aoeping 194 | release 3 195 | 196 | 2005-04-12 "Ed L. Cashin" 197 | add aoeping, a userland tool for simple AoE communications 198 | release 2 199 | 200 | 2005-03-23 "Ed L. Cashin" 201 | initial release of aoetools, version 1 202 | -------------------------------------------------------------------------------- /aoeping.c: -------------------------------------------------------------------------------- 1 | /* aoeping.c - userland aoe pinger 2 | * Copyright 2009, CORAID, Inc., and licensed under GPL v.2. 3 | * 4 | * run without arguments for usage 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "dat.h" 16 | #include "fns.h" 17 | 18 | struct progopts { 19 | int shelf; 20 | int slot; 21 | char *netif; 22 | int verbose; 23 | int timeout; 24 | u32 tag; 25 | char *smart; 26 | char ata_ident; 27 | char pp_ataid; /* pretty print ATA device identify response */ 28 | }; 29 | 30 | static struct progopts defaults = { 31 | .shelf = 0, 32 | .slot = 0, 33 | .netif = NULL, 34 | .verbose = 0, 35 | .timeout = 0, 36 | .tag = 0, 37 | .smart = NULL, 38 | .ata_ident = 0, 39 | .pp_ataid = 0, 40 | }; 41 | static struct progopts opts; 42 | 43 | struct smartcmd { 44 | char *name; /* subcommand name from ATA spec */ 45 | int cmd; /* for features register */ 46 | char data; /* does this subcommand xfer data? */ 47 | }; 48 | static struct smartcmd smarts[] = { 49 | { "read_data", 0xd0, SmartDataRet }, 50 | // { "attr_autosave", 0xd2, 0 }, (unsupported b/c it overloads sector count) 51 | { "offline_immediate", 0xd4, 0 }, 52 | { "read_log", 0xd5, SmartDataRet }, 53 | { "write_log", 0xd6, SmartDataPut }, 54 | { "enable", 0xd8, 0 }, 55 | { "disable", 0xd9, 0 }, 56 | { "return_status", 0xda, 0 }, 57 | }; 58 | 59 | static char *progname; 60 | static int sfd; /* raw socket file descriptor */ 61 | static uchar mac[6]; 62 | 63 | void 64 | usage(void) 65 | { 66 | fprintf(stderr, 67 | "usage:\t%s [options] {shelf} {slot} {netif}\n", 68 | progname); 69 | fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n\t%s\n", 70 | "options:", 71 | "-i\tdo ATA device identify dump as raw hex", 72 | "-I\tdo ATA device identify print fields", 73 | "-v\tbe verbose", 74 | "-h\tshow this usage summary"); 75 | fprintf(stderr, "%s\n\t%s\n\t%s\n\t%s\n", 76 | "options taking arguments:", 77 | "-s\ttimeout in seconds", 78 | "-S\tperform SMART command", 79 | "-t\tspecify number for starting AoE tag"); 80 | } 81 | 82 | void 83 | hex_print(FILE *out, uchar *buf, int n, char *sep) 84 | { 85 | int i; 86 | int per_line = 16; 87 | 88 | for (i = 0; i < n;) { 89 | fprintf(out, "%02x%s", *buf++ & 0xff, sep); 90 | if (!(++i % per_line)) 91 | putc('\n', out); 92 | } 93 | } 94 | 95 | void 96 | find_blade(Conf *c, struct progopts *opts) 97 | { 98 | int n; 99 | uchar buf[1400]; 100 | u32 tag; 101 | 102 | Aoehdr *h = &c->h; 103 | 104 | memset(h, 0, sizeof *h); 105 | memset(h->dst, 0xff, sizeof h->dst); 106 | memmove(h->src, mac, sizeof h->src); 107 | 108 | h->type = htons(AOE_ETH_PROTO); 109 | h->flags = AoEver << 4; 110 | h->maj = htons(opts->shelf); 111 | h->min = opts->slot; 112 | h->cmd = Config; 113 | tag = htonl(opts->tag); 114 | memmove(h->tag, &tag, sizeof h->tag); 115 | c->bufcnt = 0; 116 | c->firmware = 0; 117 | c->scnt = 0; 118 | c->vercmd = Qread; 119 | c->len = htons(1024); 120 | memset(c->data, 0xED, sizeof c->data); 121 | if (write(sfd, c, sizeof *c) == -1) { 122 | perror("send config query"); 123 | exit(EXIT_FAILURE); 124 | } 125 | for (;;) { 126 | n = read(sfd, buf, sizeof buf); 127 | if (n < 0) { 128 | perror("read network"); 129 | exit(EXIT_FAILURE); 130 | } 131 | if (n < 60) 132 | continue; 133 | h = (Aoehdr *) buf; 134 | if (ntohs(h->type) != AOE_ETH_PROTO 135 | || ntohs(h->maj) != opts->shelf 136 | || h->min != opts->slot 137 | || memcmp(h->tag, &tag, sizeof h->tag)) 138 | continue; 139 | break; 140 | } 141 | if (opts->verbose) { 142 | puts("config query response:"); 143 | hex_print(stdout, buf, n, " "); 144 | putchar('\n'); 145 | } 146 | memcpy(c, buf, sizeof *c); 147 | } 148 | 149 | /* read a packet that was sent by the device that returned *c earlier 150 | */ 151 | int 152 | aoe_pkt_read(uchar *buf, size_t siz, Conf *c, u32 tag) 153 | { 154 | Aoehdr *h; 155 | int n; 156 | 157 | tag = htonl(tag); 158 | for (;;) { 159 | n = read(sfd, buf, siz); 160 | if (n < 0) { 161 | perror("read network"); 162 | exit(EXIT_FAILURE); 163 | } 164 | if (n < 60) 165 | continue; 166 | h = (Aoehdr *) buf; 167 | if (ntohs(h->type) != AOE_ETH_PROTO 168 | || h->maj != c->h.maj 169 | || h->min != c->h.min 170 | || memcmp(&tag, h->tag, sizeof h->tag)) 171 | continue; 172 | break; 173 | } 174 | return n; 175 | } 176 | 177 | /* prepare a packet for doing ATA to a device that gave us Conf *c 178 | */ 179 | void 180 | ata_prep(Ata *a, Conf *c, u32 tag) 181 | { 182 | memset(a, 0, sizeof *a); 183 | memcpy(a->h.dst, c->h.src, sizeof a->h.dst); 184 | memcpy(a->h.src, mac, sizeof a->h.src); 185 | a->h.type = htons(AOE_ETH_PROTO); 186 | a->h.flags = AoEver << 4; 187 | a->h.maj = c->h.maj; 188 | a->h.min = c->h.min; 189 | a->h.cmd = ATAcmd; 190 | tag = htonl(tag); 191 | memmove(a->h.tag, &tag, sizeof a->h.tag); 192 | } 193 | 194 | /* pretty print ATA device identify text field 195 | * bytes have already been swapped 196 | */ 197 | void 198 | pp_idtext(char *prefix, unsigned char *p, size_t len) 199 | { 200 | int i; 201 | 202 | fputs(prefix, stdout); 203 | for (i = 0; i < len; ++i, ++p) { 204 | if (*p == '\0') 205 | break; 206 | if (!isgraph((int) *p) && *p != ' ') 207 | break; 208 | putchar(*p); 209 | } 210 | putchar('\n'); 211 | } 212 | 213 | int smart_supported(unsigned char *p) 214 | { 215 | u16 w; 216 | 217 | p += 82 * 2; /* skip to word 82 */ 218 | w = *p++; 219 | w |= *p << 8; 220 | 221 | /* word 82 bit 0 is SMART support per ATA spec */ 222 | return !!(w & 1); 223 | } 224 | 225 | void 226 | disk_identify(Conf *c, struct progopts *opts, int *smart) 227 | { 228 | int n; 229 | uchar buf[1400]; 230 | Ata a; 231 | Ata *p; 232 | struct hd_driveid *id; 233 | 234 | ata_prep(&a, c, opts->tag); 235 | a.sectors = 1; 236 | a.cmd = ATAid_dev; 237 | a.lba[3] = 0xa0; 238 | 239 | if (write(sfd, &a, sizeof a) == -1) { 240 | perror("send ATA identify device"); 241 | exit(EXIT_FAILURE); 242 | } 243 | 244 | n = aoe_pkt_read(buf, sizeof buf, c, opts->tag); 245 | p = (Ata *) buf; 246 | 247 | *smart = smart_supported(p->data); 248 | 249 | if (opts->ata_ident && !opts->pp_ataid) { 250 | puts("device identify response:"); 251 | hex_print(stdout, p->data, 512, " "); 252 | return; 253 | } 254 | if (!opts->pp_ataid) 255 | return; 256 | 257 | for (n = 0; n < 1024; n += 2) { 258 | unsigned char ch; 259 | ch = p->data[n]; 260 | p->data[n] = p->data[n+1]; 261 | p->data[n+1] = ch; 262 | } 263 | id = (struct hd_driveid *) p->data; 264 | puts("device identify fields:"); 265 | printf("vendor_specific_0: 0x%X\n", id->vendor0); 266 | printf("vendor_specific_1: 0x%X\n", id->vendor1); 267 | printf("vendor_specific_2: 0x%X\n", id->vendor2); 268 | pp_idtext("serial_number: ", id->serial_no, sizeof id->serial_no); 269 | pp_idtext("firmware_rev: ", id->fw_rev, sizeof id->fw_rev); 270 | pp_idtext("model: ", id->model, sizeof id->model); 271 | } 272 | 273 | struct smartcmd * 274 | smartcmd_lookup(char *nam) 275 | { 276 | int n = sizeof smarts / sizeof smarts[0]; 277 | int i; 278 | 279 | for (i = 0; i < n; ++i) { 280 | char *p = strchr(nam, ':'); 281 | 282 | if (p && !strncmp(smarts[i].name, nam, p - nam)) 283 | return &smarts[i]; 284 | else if (!strcmp(smarts[i].name, nam)) 285 | return &smarts[i]; 286 | } 287 | return nil; 288 | } 289 | 290 | void 291 | smart_registers(Ata *a, char *opts, struct smartcmd *s) 292 | { 293 | a->err = s->cmd; 294 | a->lba[1] = 0x4f; 295 | a->lba[2] = 0xc2; 296 | if (opts++) 297 | a->lba[0] = strtol(opts, NULL, 0); 298 | } 299 | 300 | int 301 | show_smart_regs(Ata *a) 302 | { 303 | if (a->err & ATAabrt) { 304 | fputs("SMART command aborted on target.\n", 305 | stderr); 306 | return -1; 307 | } 308 | 309 | puts("ATA registers:"); 310 | char *names[] = { 311 | "Features", "Sector Count", 312 | "LBA Low", "LBA Mid", "LBA High", 313 | "Status", 314 | }; 315 | int regs[] = { 316 | a->err, a->sectors, 317 | a->lba[0], a->lba[1], a->lba[2], 318 | a->cmd, 319 | }; 320 | int i; 321 | 322 | for (i = 0; i < sizeof regs / sizeof regs[0]; ++i) 323 | printf("%20s: 0x%02x\n", names[i], regs[i]); 324 | 325 | return 0; 326 | } 327 | 328 | void 329 | smart(Conf *c, u32 tag, char *smart_cmd) 330 | { 331 | int n; 332 | uchar buf[1400]; 333 | Ata a; 334 | Ata *p; 335 | struct smartcmd *s = smartcmd_lookup(smart_cmd); 336 | 337 | if (!s) { 338 | fprintf(stderr, 339 | "%s Error: no such SMART command: %s\n", 340 | progname, smart_cmd); 341 | exit(EXIT_FAILURE); 342 | } 343 | 344 | ata_prep(&a, c, tag); 345 | a.sectors = !!s->data; /* we only support one-sector data xfer */ 346 | a.cmd = ATAsmart; 347 | smart_registers(&a, strchr(smart_cmd, ':'), s); 348 | if (s->data & SmartDataPut) { 349 | if (read(STDIN_FILENO, a.data, 512) == -1) { 350 | perror("reading smart data from stdin"); 351 | exit(EXIT_FAILURE); 352 | } 353 | a.h.flags |= Write; 354 | } 355 | 356 | if (write(sfd, &a, sizeof a) == -1) { 357 | perror("send ATA identify device"); 358 | exit(EXIT_FAILURE); 359 | } 360 | n = aoe_pkt_read(buf, sizeof buf, c, tag); 361 | p = (Ata *) buf; 362 | /* We're expecting the AoE and ATA header plus 512 bytes of SMART */ 363 | if (n < 512 + (&p->data[0] - (uchar *) p)) 364 | exit(EXIT_FAILURE); 365 | if (show_smart_regs(p) != 0) 366 | exit(EXIT_FAILURE); 367 | if (s->data & SmartDataRet) { 368 | puts("SMART data:"); 369 | hex_print(stdout, p->data, 512, " "); 370 | } 371 | } 372 | 373 | void 374 | bad_option(char c) 375 | { 376 | fprintf(stderr, "%s Error: unrecognized option: ", progname); 377 | if (isprint(c)) 378 | fprintf(stderr, "%c\n", c); 379 | else 380 | fprintf(stderr, "0x%02x\n", c & 0xff); 381 | } 382 | 383 | void 384 | check_timeout(int secs) 385 | { 386 | if (secs < 1) { 387 | fprintf(stderr, 388 | "%s Error: timeout seconds must be one or more\n", 389 | progname); 390 | exit(EXIT_FAILURE); 391 | } 392 | } 393 | 394 | void 395 | init_opts(struct progopts *opts, int argc, char *argv[]) 396 | { 397 | int c; 398 | 399 | while ( (c = getopt(argc, argv, "hviIt:s:S:")) != -1) { 400 | switch (c) { 401 | case 'h': 402 | usage(); 403 | exit(EXIT_SUCCESS); 404 | break; 405 | case 'v': 406 | ++opts->verbose; 407 | break; 408 | case 'i': 409 | opts->ata_ident = 1; 410 | break; 411 | case 'I': 412 | opts->ata_ident = 1; 413 | opts->pp_ataid = 1; 414 | break; 415 | case 't': 416 | opts->tag = atoi(optarg); 417 | break; 418 | case 's': 419 | opts->timeout = atoi(optarg); 420 | check_timeout(opts->timeout); 421 | break; 422 | case 'S': 423 | opts->smart = optarg; 424 | break; 425 | case '?': 426 | bad_option(optopt); 427 | usage(); 428 | exit(EXIT_FAILURE); 429 | break; 430 | default: 431 | abort(); /* shouldn't happen */ 432 | } 433 | } 434 | if (argc - optind != 3) { 435 | usage(); 436 | exit(EXIT_FAILURE); 437 | } 438 | opts->shelf = atoi(argv[optind]); 439 | opts->slot = atoi(argv[optind+1]); 440 | opts->netif = argv[optind+2]; 441 | } 442 | 443 | int 444 | main(int argc, char *argv[]) 445 | { 446 | Conf c; 447 | int smartable = 0; 448 | 449 | opts = defaults; 450 | progname = strrchr(argv[0], '/'); 451 | if (progname) 452 | progname += 1; 453 | else 454 | progname = argv[0]; 455 | 456 | init_opts(&opts, argc, argv); 457 | opts.tag |= 1UL << 31; /* set high bit for userland AoE */ 458 | 459 | if (opts.verbose) { 460 | printf("tag: %x\neth: %s\nshelf: %u\nslot: %u\n", 461 | opts.tag, opts.netif, opts.shelf, opts.slot); 462 | fflush(stdout); 463 | } 464 | sfd = dial(opts.netif); 465 | if (!getea(sfd, opts.netif, mac)) 466 | exit(EXIT_FAILURE); 467 | 468 | alarm(opts.timeout); 469 | find_blade(&c, &opts); 470 | opts.tag += 1; 471 | alarm(0); 472 | if (opts.verbose) { 473 | printf("found e%d.%d with mac ", 474 | ntohs(c.h.maj), c.h.min); 475 | hex_print(stdout, c.h.src, sizeof c.h.src, ""); 476 | putchar('\n'); 477 | fflush(stdout); 478 | } 479 | 480 | if (opts.ata_ident || opts.smart) { 481 | alarm(opts.timeout); 482 | disk_identify(&c, &opts, &smartable); 483 | alarm(0); 484 | opts.tag += 1; 485 | } 486 | 487 | if (opts.smart) { 488 | if (!smartable) { 489 | fprintf(stderr, 490 | "Error: e%d.%d does not support SMART\n", 491 | ntohs(c.h.maj), c.h.min); 492 | exit(EXIT_FAILURE); 493 | } 494 | alarm(opts.timeout); 495 | smart(&c, opts.tag, opts.smart); 496 | alarm(0); 497 | opts.tag += 1; 498 | } 499 | 500 | return 0; 501 | } 502 | -------------------------------------------------------------------------------- /aoe-sancheck.c: -------------------------------------------------------------------------------- 1 | /* Copyright Coraid, Inc. 2010. All Rights Reserved. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define nelem(x) (sizeof(x)/sizeof((x)[0])) 25 | #define nil NULL 26 | #define vprintf(...) if (qflag) ; else fprintf(stderr, __VA_ARGS__) 27 | #define mintu(x) ((x) > 60 ? x : 60) 28 | 29 | typedef unsigned char uchar; 30 | typedef unsigned long ulong; 31 | 32 | typedef struct Aoe Aoe; 33 | typedef struct Qc Qc; 34 | typedef struct Ata Ata; 35 | typedef struct Lun Lun; 36 | typedef struct Eth Eth; 37 | typedef struct Targ Targ; 38 | typedef struct Mac Mac; 39 | 40 | struct Aoe { 41 | uchar dst[6]; 42 | uchar src[6]; 43 | uchar type[2]; 44 | uchar flags; 45 | uchar error; 46 | uchar major[2]; 47 | uchar minor; 48 | uchar cmd; 49 | uchar tag[4]; 50 | }; 51 | 52 | struct Qc { 53 | Aoe h; 54 | uchar bufcnt[2]; 55 | uchar firmware[2]; 56 | uchar scnt; 57 | uchar vercmd; 58 | uchar len[2]; 59 | // uchar data[1024]; 60 | }; 61 | 62 | 63 | struct Ata { 64 | Aoe h; 65 | uchar aflag; 66 | uchar err; 67 | uchar scnt; 68 | uchar cmd; 69 | uchar lba[6]; 70 | uchar res[2]; 71 | }; 72 | 73 | struct Lun { 74 | Lun *next; 75 | int state; 76 | char ea[6]; 77 | int major; 78 | int minor; 79 | int nsect; 80 | int maxsect; 81 | int id; 82 | }; 83 | 84 | struct Eth { 85 | Lun *luns; 86 | int fd; 87 | char *name; 88 | char ea[6]; 89 | int mtu; 90 | int up; 91 | uchar pkt[16*1024]; 92 | }; 93 | 94 | struct Targ { 95 | Targ *next; 96 | int major; 97 | int minor; 98 | }; 99 | 100 | struct Mac { 101 | Mac *next; 102 | char ea[6]; 103 | }; 104 | 105 | enum { 106 | Neth= 32, 107 | Nstack= 16*1024, 108 | Nws= 5, 109 | 110 | Lnew= 0, 111 | Lprobe, 112 | 113 | Arsp= (1<<3), 114 | Aerr= (1<<2), 115 | 116 | Cata= 0, 117 | Cqc= 1, 118 | 119 | ETaoe= 0x88a2, 120 | }; 121 | 122 | int ethlist(char **, int); 123 | int ethopen(Eth *); 124 | void *jcheck(void *); 125 | int jinput(Eth *); 126 | Lun *findlun(Eth *e, Aoe *a); 127 | void jprobe(Eth *e, Lun *lun); 128 | void printlist(void); 129 | void printsancheck(void); 130 | ulong nhgetl(uchar *); 131 | ushort nhgets(uchar *); 132 | void hnputs(uchar *, ushort); 133 | void hnputl(uchar *, ulong); 134 | void *mallocz(int); 135 | void inserttarg(int, int); 136 | void insertmac(Mac **, char *); 137 | void sancheck(int, int); 138 | void ifsummary(void); 139 | int ifup(char *); 140 | void inserteth(char **, int, char *); 141 | char *getpciid(char *, int, char *); 142 | 143 | Eth eth[Neth]; 144 | int waitsecs = Nws; 145 | pthread_t threads[Neth]; 146 | Targ *targlist; 147 | 148 | int 149 | main(int argc, char **argv) 150 | { 151 | int n, i; 152 | char *ethnames[Neth]; 153 | Eth *e; 154 | 155 | memset(ethnames, 0, sizeof ethnames); 156 | printf("Probing..."); 157 | fflush(0); 158 | n = ethlist(ethnames, nelem(ethnames)); 159 | for (i=0; iname = ethnames[i]; 162 | e->up = ifup(ethnames[i]); 163 | if (pthread_create(&threads[i], 0, jcheck, e)) { 164 | fprintf(stderr, "pthread_create failed.\n"); 165 | break; 166 | } 167 | } 168 | n = i; 169 | for (i=0; i> 4) & 0xf)]; 187 | *p++ = hex[ea[i] & 0xf]; 188 | } 189 | *p = 0; 190 | return op; 191 | } 192 | 193 | void 194 | printlist(void) 195 | { 196 | Eth *e; 197 | Lun *lun; 198 | char mac[13]; 199 | 200 | for (e=eth; e->name; e++) { 201 | printf("%s:\n", e->name); 202 | for (lun=e->luns; lun; lun=lun->next) 203 | printf("e%d.%d %s %d\n", lun->major, lun->minor, cea(mac, lun->ea), lun->maxsect); 204 | printf("\n"); 205 | } 206 | } 207 | 208 | void 209 | timewait(int secs) /* arrange for a sig_alarm signal after `secs' seconds */ 210 | { 211 | struct sigaction sa; 212 | void catch(int); 213 | 214 | memset(&sa, 0, sizeof sa); 215 | sa.sa_handler = catch; 216 | sa.sa_flags = SA_RESETHAND; 217 | sigaction(SIGALRM, &sa, NULL); 218 | alarm(secs); 219 | } 220 | 221 | int 222 | discover(Eth *e) 223 | { 224 | Aoe *a; 225 | Qc *q; 226 | 227 | memset(e->pkt, 0, sizeof e->pkt); 228 | a = (Aoe *) e->pkt; 229 | memset(a->dst, 0xff, 6); 230 | memmove(a->src, e->ea, 6); 231 | hnputs(a->type, ETaoe); 232 | hnputl(a->tag, 1<<31); 233 | hnputs(a->major, 0xffff); 234 | a->minor = 0xff; 235 | a->cmd = Cqc; 236 | a->flags = 0x10; 237 | if (write(e->fd, a, mintu(sizeof *q)) <= 0) 238 | return -1; 239 | return 0; 240 | } 241 | 242 | void * 243 | jcheck(void *v) 244 | { 245 | Eth *e = v; 246 | int n; 247 | time_t t, nt; 248 | struct pollfd pd; 249 | 250 | if (ethopen(e) < 0) 251 | return 0; 252 | if (discover(e) < 0) { 253 | fprintf(stderr, "skipping %s, discover failure: %s\n", e->name, strerror(errno)); 254 | return 0; 255 | } 256 | 257 | pd.fd = e->fd; 258 | pd.events = POLLIN; 259 | t = time(0); 260 | for (;;) { 261 | nt = time(0); 262 | if (nt-t >= waitsecs) 263 | return 0; 264 | if (poll(&pd, 1, waitsecs*1000) > 0) 265 | if ((n = read(e->fd, e->pkt, sizeof e->pkt)) > 0) 266 | if (jinput(e)) 267 | t = time(0); 268 | } 269 | } 270 | 271 | /* return 1 == useful, 0 == not useful */ 272 | int 273 | jinput(Eth *e) 274 | { 275 | Aoe *a; 276 | Qc *q; 277 | Lun *lun; 278 | ulong tag; 279 | int n; 280 | 281 | a = (Aoe *) e->pkt; 282 | if ((a->flags & (Arsp|Aerr)) != Arsp) 283 | return 0; 284 | if ((a->tag[0] & 0x80) == 0) 285 | return 0; 286 | tag = nhgetl(a->tag); 287 | switch (a->cmd) { 288 | case Cqc: 289 | q = (Qc *) a; 290 | lun = findlun(e, a); 291 | if (lun->state == Lnew) { 292 | lun->nsect = q->scnt; 293 | jprobe(e, lun); 294 | lun->state = Lprobe; 295 | break; 296 | } 297 | return 0; 298 | case Cata: 299 | lun = findlun(e, a); 300 | if (lun == nil) 301 | return 0; 302 | if (lun->id != tag>>16) { 303 | printf("lun->id %d != tag %ld for %d.%d\n", lun->id, tag>>16, lun->major, lun->minor); 304 | return 0; 305 | } 306 | n = tag & 0xff; 307 | if (n > lun->maxsect) 308 | lun->maxsect = n; 309 | break; 310 | default: 311 | return 0; 312 | } 313 | return 1; 314 | } 315 | 316 | void 317 | hnputl(uchar *p, ulong n) 318 | { 319 | *p++ = n >> 24; 320 | *p++ = n >> 16; 321 | *p++ = n >> 8; 322 | *p = n; 323 | } 324 | 325 | void 326 | hnputs(uchar *p, ushort s) 327 | { 328 | *p++ = s >> 8; 329 | *p = s; 330 | } 331 | 332 | ushort 333 | nhgets(uchar *p) 334 | { 335 | ushort s; 336 | 337 | s = *p++; 338 | s <<= 8; 339 | s += *p++ & 0xff; 340 | return s; 341 | } 342 | 343 | ulong 344 | nhgetl(uchar *p) 345 | { 346 | ulong n; 347 | 348 | n = *p++; 349 | n <<= 8; 350 | n += *p++ & 0xff; 351 | n <<= 8; 352 | n += *p++ & 0xff; 353 | n <<= 8; 354 | n += *p++ & 0xff; 355 | return n; 356 | } 357 | 358 | void 359 | jprobe(Eth *e, Lun *lun) 360 | { 361 | Aoe *a; 362 | Ata *aa; 363 | int n; 364 | 365 | memset(e->pkt, 0, sizeof e->pkt); 366 | a = (Aoe *) e->pkt; 367 | aa = (Ata *) a; 368 | memcpy(a->dst, lun->ea, 6); 369 | memcpy(a->src, e->ea, 6); 370 | hnputs(a->type, ETaoe); 371 | hnputs(a->major, lun->major); 372 | a->minor = lun->minor; 373 | a->flags = 0x10; 374 | hnputl(a->tag, lun->id<<16); 375 | aa->cmd = 0xec; 376 | aa->scnt = 1; 377 | n = e->mtu - sizeof *aa; 378 | for (n &= ~511; n > 0; n -= 512) { 379 | a->tag[3] = n/512; 380 | if (write(e->fd, a, sizeof *aa + n) <= 0) { 381 | printf("write failed\n"); 382 | } 383 | usleep(100); 384 | } 385 | } 386 | 387 | Lun * 388 | findlun(Eth *e, Aoe *a) 389 | { 390 | Lun *p, **pp; 391 | int maj, n; 392 | static int id; 393 | 394 | maj = nhgets(a->major); 395 | pp = &e->luns; 396 | for (; (p=*pp); pp=&p->next) { 397 | if (maj < p->major) 398 | continue; 399 | if (maj > p->major) 400 | break; 401 | if (a->minor < p->minor) 402 | continue; 403 | if (a->minor > p->minor) 404 | break; 405 | n = memcmp(p->ea, a->src, 6); 406 | if (n < 0) 407 | continue; 408 | if (n > 0) 409 | break; 410 | return p; 411 | } 412 | if (a->cmd == Cata) 413 | return nil; 414 | p = mallocz(sizeof *p); 415 | p->major = maj; 416 | p->minor = a->minor; 417 | memmove(p->ea, a->src, 6); 418 | p->next = *pp; 419 | p->id = 0x8000 | id++; 420 | inserttarg(p->major, p->minor); 421 | return *pp = p; 422 | } 423 | 424 | 425 | void 426 | catch(int sig) 427 | { 428 | } 429 | 430 | int 431 | getindx(int sfd, char *name) // return the index of device 'name' 432 | { 433 | struct ifreq xx; 434 | int n; 435 | 436 | strcpy(xx.ifr_name, name); 437 | n = ioctl(sfd, SIOCGIFINDEX, &xx); 438 | if (n == -1) 439 | return -1; 440 | return xx.ifr_ifindex; 441 | } 442 | 443 | int 444 | getmtu(Eth *e) 445 | { 446 | struct ifreq xx; 447 | int n; 448 | 449 | strcpy(xx.ifr_name, e->name); 450 | n = ioctl(e->fd, SIOCGIFMTU, &xx); 451 | if (n == -1) { 452 | perror("Can't get mtu"); 453 | return 1500; 454 | } 455 | return xx.ifr_mtu; 456 | } 457 | 458 | int 459 | ethopen(Eth *e) // get us a raw connection to an interface 460 | { 461 | int n, sfd, rbsz, sbsz; 462 | struct sockaddr_ll sa; 463 | struct ifreq xx; 464 | 465 | rbsz = 64*1024*1024; 466 | sbsz = 64*1024*1024; 467 | memset(&sa, 0, sizeof sa); 468 | memset(&xx, 0, sizeof xx); 469 | sfd = socket(PF_PACKET, SOCK_RAW, htons(ETaoe)); 470 | if (sfd == -1) { 471 | perror("got bad socket"); 472 | return -1; 473 | } 474 | if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUFFORCE, &rbsz, sizeof rbsz) < 0) 475 | fprintf(stderr, "Failed to set socket rcvbuf size\n"); 476 | if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUFFORCE, &sbsz, sizeof sbsz) < 0) 477 | fprintf(stderr, "Failed to set socket sndbuf size\n"); 478 | n = getindx(sfd, e->name); 479 | sa.sll_family = AF_PACKET; 480 | sa.sll_protocol = htons(ETaoe); 481 | sa.sll_ifindex = n; 482 | n = bind(sfd, (struct sockaddr *)&sa, sizeof sa); 483 | if (n == -1) { 484 | perror("bind funky"); 485 | return -1; 486 | } 487 | strcpy(xx.ifr_name, e->name); 488 | n = ioctl(sfd, SIOCGIFHWADDR, &xx); 489 | if (n == -1) { 490 | perror("Can't get hw addr"); 491 | return -1; 492 | } 493 | memmove(e->ea, xx.ifr_hwaddr.sa_data, 6); 494 | e->fd = sfd; 495 | e->mtu = getmtu(e); 496 | return 0; 497 | } 498 | 499 | int 500 | ethlist(char **ifs, int nifs) 501 | { 502 | int s, n; 503 | struct ifreq ifr; 504 | struct if_nameindex *if_ni, *i; 505 | 506 | s = socket(AF_INET, SOCK_STREAM, 0); 507 | if (s < 0) 508 | return 0; 509 | 510 | if_ni = if_nameindex(); 511 | if (if_ni == NULL) 512 | return 0; 513 | 514 | n = 0; 515 | for (i = if_ni; ! (i->if_index == 0 && i->if_name == NULL); i++) { 516 | memset(&ifr, 0, sizeof ifr); 517 | ifr.ifr_ifindex = i->if_index; 518 | strcpy(ifr.ifr_name, i->if_name); 519 | // get interface flags 520 | if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) 521 | continue; 522 | // only use interfaces that use arp protocol 523 | if (ifr.ifr_flags & IFF_NOARP) 524 | continue; 525 | // skip loopback interfaces 526 | if (ifr.ifr_flags & IFF_LOOPBACK) 527 | continue; 528 | if (n == nifs) 529 | break; 530 | inserteth(ifs, nifs, ifr.ifr_name); 531 | n++; 532 | } 533 | if_freenameindex(if_ni); 534 | close(s); 535 | return n; 536 | } 537 | 538 | void * 539 | mallocz(int sz) 540 | { 541 | void *p; 542 | 543 | p = malloc(sz); 544 | memset(p, 0, sz); 545 | return p; 546 | } 547 | 548 | void 549 | inserttarg(int maj, int min) 550 | { 551 | Targ *nt, *t, *p; 552 | 553 | nt = mallocz(sizeof *nt); 554 | nt->major = maj; 555 | nt->minor = min; 556 | if (targlist == NULL) { 557 | targlist = nt; 558 | return; 559 | } 560 | if (nt->major < targlist->major) { 561 | nt->next = targlist; 562 | targlist = nt; 563 | return; 564 | } else if (nt->major == targlist->major && nt->minor < targlist->minor) { 565 | nt->next = targlist; 566 | targlist = nt; 567 | return; 568 | } else if (nt->major == targlist->major && nt->minor == targlist->minor) 569 | return; 570 | for (p = targlist,t = targlist->next; t; p = t,t = t->next) { 571 | if (nt->major == t->major && nt->minor == t->minor) 572 | return; 573 | if (nt->major < t->major) { 574 | p->next = nt; 575 | nt->next = t; 576 | return; 577 | } else if (nt->major == t->major && nt->minor < t->minor) { 578 | p->next = nt; 579 | nt->next = t; 580 | return; 581 | } 582 | } 583 | p->next = nt; 584 | } 585 | 586 | void 587 | printsancheck() 588 | { 589 | Targ *t; 590 | 591 | printf("==========================================\n"); 592 | printf("INTERFACE SUMMARY\n"); 593 | printf("==========================================\n"); 594 | printf("Name\tStatus\tMTU\tPCI ID\n"); 595 | ifsummary(); 596 | printf("==========================================\n"); 597 | printf("DEVICE SUMMARY\n"); 598 | printf("==========================================\n"); 599 | printf("Device\tMacs\tPayload\tLocal Interfaces\n"); 600 | for (t = targlist; t; t = t->next) { 601 | sancheck(t->major, t->minor); 602 | } 603 | } 604 | 605 | void 606 | ifsummary() 607 | { 608 | Eth *e; 609 | char buf[32]; 610 | char *p; 611 | 612 | for (e=eth; e->name; e++) { 613 | p = getpciid(buf, sizeof buf, e->name); 614 | printf("%s\t%s\t%d\t%s\n", e->name, (e->up ? "UP" : "DN"), e->mtu, (p ? p : "")); 615 | } 616 | 617 | } 618 | 619 | void 620 | sancheck(int maj, int min) 621 | { 622 | Eth *e; 623 | Lun *l; 624 | Mac *ml, *m; 625 | int a, found; 626 | int ps, nsect, nea, nloc; 627 | int mtu; 628 | char buf[128]; 629 | char mac[13]; 630 | 631 | nsect = mtu = 0; 632 | nloc = nea = 0; 633 | a = 0; 634 | ps = 0; 635 | memset(buf, 0, sizeof buf); 636 | ml = NULL; 637 | 638 | for (e=eth; e->name; e++) { 639 | found = 0; 640 | for (l = e->luns; l; l = l->next) { 641 | if (!(l->major == maj && l->minor == min)) 642 | continue; 643 | found = 1; 644 | if (mtu == 0) 645 | mtu = e->mtu; 646 | else if (mtu != e->mtu) 647 | mtu = (e->mtu > mtu ? e->mtu : mtu); 648 | 649 | insertmac(&ml, l->ea); 650 | if (ps == 0) 651 | ps = l->maxsect; 652 | else 653 | ps = (l->maxsect < ps ? l->maxsect : ps); 654 | nsect = l->nsect; 655 | } 656 | if (found) { 657 | snprintf(buf + a,(sizeof buf) - a, "%s%s", (a ? ",": ""), e->name); 658 | a += strlen(e->name) + (a ? 1 : 0); 659 | nloc++; 660 | } 661 | } 662 | for (m = ml; m; ml = m, nea++) { 663 | m = m->next; 664 | free(ml); 665 | } 666 | printf("e%d.%d\t%4d\t%d\t%s\n", maj, min, nea, nsect*512, buf); 667 | if (nea != nloc) 668 | printf(" Mismatched number of local vs remote interfaces\n"); 669 | for (e=eth; e->name; e++) { 670 | found = 0; 671 | for (l = e->luns; l; l = l->next) 672 | if (l->major == maj && l->minor == min) { 673 | found = 1; 674 | if (l->maxsect < (e->mtu-32)/512) 675 | printf(" The path %s->%s is only capable of %d byte payloads\n", e->name, cea(mac, l->ea), l->maxsect*512); 676 | } 677 | if (found) { 678 | if (e->mtu < nsect*512 + 36) 679 | printf(" %s: MTU (%d) not set optimally for device's capable payload\n",e->name, e->mtu); 680 | if (e->mtu < mtu) 681 | printf(" %s: MTU different from other interfaces (%d vs. %d)\n", e->name, e->mtu, mtu); 682 | } 683 | } 684 | } 685 | 686 | void 687 | insertmac(Mac **ml, char *m) 688 | { 689 | Mac *nm,*p, *pp; 690 | 691 | for (p = *ml, pp=NULL; p; pp = p, p = p->next) 692 | if (memcmp(p->ea, m, 6) == 0) 693 | return; 694 | nm = mallocz(sizeof *nm); 695 | memcpy(nm->ea, m, 6); 696 | if (pp) 697 | pp->next = nm; 698 | else 699 | *ml = nm; 700 | } 701 | 702 | int 703 | ifup(char *ethname) 704 | { 705 | struct ifreq ifr; 706 | int r, s; 707 | 708 | memset(&ifr, 0, sizeof ifr); 709 | s = socket(AF_INET, SOCK_STREAM, 0); 710 | if (s < 0) 711 | return 0; 712 | strcpy(ifr.ifr_name, ethname); 713 | if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { 714 | close(s); 715 | return 0; 716 | } 717 | r = ifr.ifr_flags & IFF_UP; 718 | close(s); 719 | return r; 720 | } 721 | 722 | void 723 | inserteth(char **ifs, int nifs, char *n) 724 | { 725 | int i, j; 726 | char a[64], b[64]; 727 | 728 | memset(a, 0, sizeof a); 729 | memset(b, 0, sizeof b); 730 | for (i=0; i < nifs; i++) { 731 | if (ifs[i] == 0) { 732 | ifs[i] = strdup(n); 733 | break; 734 | } 735 | j = strcmp(n, ifs[i]); 736 | if (j < 0) { 737 | strcpy(a, n); 738 | for (; ifs[i]; i++) { 739 | strcpy(b, ifs[i]); 740 | free(ifs[i]); 741 | ifs[i] = strdup(a); 742 | strcpy(a, b); 743 | } 744 | ifs[i] = strdup(a); 745 | break; 746 | } else if (j == 0) 747 | break; 748 | else if (j > 0) 749 | continue; 750 | } 751 | } 752 | 753 | char * 754 | getpciid(char *b, int blen, char *n) 755 | { 756 | FILE *fd; 757 | char dev[8]; 758 | char ven[8]; 759 | char path[128]; 760 | 761 | memset(dev, 0, sizeof dev); 762 | memset(ven, 0, sizeof ven); 763 | memset(path, 0, sizeof path); 764 | sprintf(path, "/sys/class/net/%s/device/vendor", n); 765 | if ((fd = fopen(path, "r")) == NULL) 766 | return NULL; 767 | fseek(fd, 2, SEEK_SET); 768 | if (fread(ven, 1, 4, fd) <= 0) { 769 | fclose(fd); 770 | return NULL; 771 | } 772 | fclose(fd); 773 | sprintf(path, "/sys/class/net/%s/device/device", n); 774 | if ((fd = fopen(path, "r")) == NULL) 775 | return NULL; 776 | fseek(fd, 2, SEEK_SET); 777 | if (fread(dev, 1, 4, fd) <= 0) { 778 | fclose(fd); 779 | return NULL; 780 | } 781 | fclose(fd); 782 | snprintf(b, blen, "%s:%s", ven, dev); 783 | return b; 784 | } 785 | 786 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | --------------------------------------------------------------------------------