mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
For maximum performance the MTU of an HSCI interface was set to the value
of the MTU of its HiperSockets interface. However, the MTU of a
HiperSockets interface can be very large, and when the data packets are
not sent over the HiperSocket but over the corresponding ethernet
interface (which usually has a smaller MTU size) then it can happen that
the large packets are silently dropped. One example would be communication
from an HSCI in one CEC to another HSCI in another CEC via Ethernet.
To solve the problem, the MTU setting in this tool is removed, and the
default MTU value is used. Thus, the minimum value of the MTUs of the both
converged interfaces is used as the MTU of the HSCI interface.
Fixes: 0566a492ae ("s390-tools: add hsci tool")
Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
437 lines
12 KiB
Bash
Executable File
437 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# hsci - Tool to manage HiperSockets Converged Interfaces (HSCI)
|
|
#
|
|
# Copyright IBM Corp. 2020
|
|
#
|
|
# s390-tools is free software; you can redistribute it and/or modify
|
|
# it under the terms of the MIT license. See LICENSE for details.
|
|
#
|
|
|
|
hsdev=""
|
|
ndev=""
|
|
hsci=""
|
|
hsdev_mac=""
|
|
hsif_pnetid=""
|
|
netif_pnetid=""
|
|
hsci_pnetid=""
|
|
|
|
function usage {
|
|
cat <<-EOD
|
|
Usage: hsci COMMAND [OPTION]
|
|
|
|
This tool is designed to control and show HSCI (HiperSockets Converged
|
|
Interfaces) settings. A HiperSockets interface and an external network
|
|
interface are converged into an HSCI interface.
|
|
|
|
COMMANDS
|
|
add HIPERSOCKETS_DEV NET_DEV Adds an HSCI interface
|
|
del HSCI_NAME Deletes an HSCI interface
|
|
show Lists the configured HSCI interfaces
|
|
|
|
OPTIONS:
|
|
-v, --version Prints the version number of the hsci tool and exits
|
|
-h, --help Displays the help information for the command
|
|
EOD
|
|
}
|
|
|
|
function prereqs_check {
|
|
if ! [ -x "$(command -v ip)" ]; then
|
|
echo "Error: No iproute2 installed on this system" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function check_pnetids {
|
|
# get PNETID of the HS
|
|
local hsif_pnetids=""
|
|
local netif_pnetids=""
|
|
|
|
if [ -e /sys/class/net/$hsdev/device/util_string ]; then
|
|
hsif_pnetids="$(cat /sys/class/net/$hsdev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
|
else
|
|
if [ -e /sys/class/net/$hsdev/device/chpid ]; then
|
|
chpid="$(cat /sys/class/net/$hsdev/device/chpid | tr [:upper:] [:lower:])"
|
|
hsif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
|
fi
|
|
fi
|
|
if [ "$hsif_pnetids" != "" ]; then
|
|
port_hsif="$(cat /sys/class/net/$hsdev/dev_port)"
|
|
(( idx=16*$port_hsif+1 ))
|
|
(( end=$idx+15 ))
|
|
hsif_pnetid="$(echo "$hsif_pnetids" | cut -c $idx-$end | tr -d ' ')"
|
|
fi
|
|
|
|
# get PNETID of the NET_DEV
|
|
if [ -e /sys/class/net/$ndev/device/util_string ]; then
|
|
netif_pnetids="$(cat /sys/class/net/$ndev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
|
else
|
|
if [ -e /sys/class/net/$ndev/device/chpid ]; then
|
|
chpid="$(cat /sys/class/net/$ndev/device/chpid | tr [:upper:] [:lower:])"
|
|
netif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
|
fi
|
|
fi
|
|
if [ "$netif_pnetids" != "" ]; then
|
|
port_netif="$(cat /sys/class/net/$ndev/dev_port)"
|
|
(( idx=16*$port_netif+1 ))
|
|
(( end=$idx+15 ))
|
|
netif_pnetid="$(echo "$netif_pnetids" | cut -c $idx-$end | tr -d ' ')"
|
|
fi
|
|
|
|
#Check PNETIDs
|
|
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" != "$hsif_pnetid" ]; then
|
|
echo "Error: $hsdev and $ndev have different PNETIDs! They are $hsif_pnetid and $netif_pnetid respectively" >&2
|
|
return 1
|
|
fi
|
|
|
|
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" == "$hsif_pnetid" ]; then
|
|
hsci_pnetid=$hsif_pnetid
|
|
fi
|
|
}
|
|
|
|
function verify_precon {
|
|
echo "Verifying net dev $ndev and HiperSockets dev $hsdev"
|
|
|
|
if [ ! -e /sys/class/net/$hsdev ]; then
|
|
echo "Error: $hsdev does not exist" >&2
|
|
return 1
|
|
fi
|
|
if [ "$(cat /sys/class/net/$hsdev/device/card_type)" != "HiperSockets" ]; then
|
|
echo "Error: $hsdev is not a HiperSockets device" >&2
|
|
return 1
|
|
fi
|
|
if [ "$(cat /sys/class/net/$hsdev/device/layer2)" != "1" ]; then
|
|
echo "Error: $hsdev is not in layer 2 mode" >&2
|
|
return 1
|
|
fi
|
|
if [ ! -e /sys/class/net/$hsdev/device/vnicc/bridge_invisible ]; then
|
|
echo "Error: Missing vnic-characteristics support" >&2
|
|
return 1
|
|
fi
|
|
if [ "$(cat /sys/class/net/$hsdev/device/vnicc/bridge_invisible)" == "n/a" ]; then
|
|
echo "Error: $hsdev does not support vnicc" >&2
|
|
return 1
|
|
fi
|
|
if [ $(ip link show $hsdev | grep UP | wc -l) -eq 0 ]; then
|
|
echo "Error: $hsdev is not in state UP" >&2
|
|
return 1
|
|
fi
|
|
if [ $(bridge -d link show dev $hsdev self | grep learning_sync | wc -l) -eq 0 ]; then
|
|
echo "Error: $hsdev does not support attribute learning_sync" >&2
|
|
return 1
|
|
fi
|
|
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
|
|
echo "Error: $hsdev is already a bridge port" >&2
|
|
return 1
|
|
fi
|
|
|
|
#Pre-verify net_dev
|
|
if [ ! -e /sys/class/net/$ndev ]; then
|
|
echo "Error: $ndev does not exist" >&2
|
|
return 1
|
|
fi
|
|
if [ "$(cat /sys/class/net/$ndev/device/card_type)" == "HiperSockets" ]; then
|
|
echo "Error: $ndev is also a HiperSockets device" >&2
|
|
return 1
|
|
fi
|
|
if [ $(ip link show $ndev | grep UP | wc -l) -eq 0 ]; then
|
|
echo "Error: $ndev is not in state UP" >&2
|
|
return 1
|
|
fi
|
|
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
|
|
echo "Error: $ndev is already a bridge port" >&2
|
|
return 1
|
|
fi
|
|
|
|
#Check PNETIDs
|
|
check_pnetids
|
|
if [ $? -ne 0 ]; then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
function clean_up {
|
|
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
|
|
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible >/dev/null 2>&1
|
|
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
|
|
ip link del $hsci >/dev/null 2>&1
|
|
}
|
|
|
|
##############################################################################
|
|
## add a new HSCI interface
|
|
##############################################################################
|
|
function add_hsci {
|
|
|
|
if [ $# != 2 ]; then
|
|
echo "hsci: Invalid parameters" >&2
|
|
echo "Use 'hsci --help' for more information" >&2
|
|
return 1
|
|
fi
|
|
hsdev=$1
|
|
ndev=$2
|
|
|
|
#### Verify preconditions
|
|
verify_precon
|
|
if [ $? -ne 0 ]; then
|
|
return 1
|
|
fi
|
|
|
|
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
|
|
hsci=hsci$hsci_postfix
|
|
|
|
echo "Adding $hsci with a HiperSockets dev $hsdev and an external dev $ndev"
|
|
|
|
#### Create bridge
|
|
ip link add name $hsci type bridge stp_state 0 >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Could not create a bridge" >&2
|
|
return 1
|
|
fi
|
|
|
|
#### Prepare hsdev
|
|
# Set VNICC of hsdev to invisible
|
|
#(mandatory for co-existence with HS-OSA bridges!)
|
|
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
|
|
|
#### Create bridge ports
|
|
ip link set dev $ndev master $hsci >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Could not set master for $ndev" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
ip link set dev $hsdev master $hsci >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Could not set master for $hsdev" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
# no forwarding between ndev and hsdev -> isolated on
|
|
# ndev is default for outgoing unknown targets -> flood on
|
|
# no need to learn external LAN targets into fdb -> learning off
|
|
bridge link set dev $ndev isolated on learning off flood on mcast_flood on >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to set bridge attributes on $ndev" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
# no forwarding between ndev and hsdev -> isolated on
|
|
# fdb will be populated by dev-to-bridge-notification, no need to learn
|
|
# -> learning off
|
|
# only send to hsdev, if listed in fdb -> flood off
|
|
# don't send MC/BC on hsdev -> mcast_flood off
|
|
bridge link set dev $hsdev isolated on learning off flood off mcast_flood off >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to set bridge attributes on $hsdev" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
# NOTE: Although not required, BCs will be sent out on hsdev.
|
|
# NOTE: We need to receive BCs on hsdev, as z/OS HSCI does ARP requests on HS.
|
|
|
|
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
|
|
echo "Set $hsdev MAC $hsdev_mac on $ndev and $hsci"
|
|
|
|
# set HS MAC on OSA as secondary MAC
|
|
bridge fdb add $hsdev_mac dev $ndev >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to set HS MAC on OSA as secondary MAC" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
# set HS MAC (common MAC) on HSCI as primary MAC
|
|
ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to set HiperSockets MAC (common MAC) on HSCI as primary MAC" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
ip link set dev $hsci up >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to set $hsci up" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
|
|
# Turn on device for bridge notification
|
|
bridge link set dev $hsdev learning_sync on self >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to turn on device for bridge notification" >&2
|
|
clean_up
|
|
return 1
|
|
fi
|
|
echo "Successfully added HSCI interface $hsci"
|
|
return 0
|
|
}
|
|
|
|
##############################################################################
|
|
## Delete HSCI
|
|
##############################################################################
|
|
|
|
function del_hsci {
|
|
if [ $# != 1 ]; then
|
|
echo "hsci: invalid parameters" >&2
|
|
echo "Use 'hsci --help' for more information" >&2
|
|
return 1
|
|
fi
|
|
hsci=$1
|
|
if [ $(ip link show dev $hsci | wc -l) -eq 0 ]; then
|
|
echo "Error: $hsci does not exit" >&2
|
|
return 1
|
|
fi
|
|
if [ $(ip link show | grep "master $hsci" | wc -l) -eq 0 ]; then
|
|
echo "Error: $hsci is not an active HSCI interface" >&2
|
|
return 1
|
|
fi
|
|
|
|
bports="$(ip link show | grep "master $hsci" | awk '{print $2}')"
|
|
for bport in $bports; do
|
|
bport=${bport%:}
|
|
if [[ $bport == *@* ]]; then
|
|
bport=${bport%@*}
|
|
fi
|
|
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
|
hsdev=$bport
|
|
else
|
|
ndev=$bport
|
|
fi
|
|
done
|
|
if [ "$hsdev" == "" ]; then
|
|
echo "Error: $hsci has no active HiperSockets port" >&2
|
|
return 1
|
|
fi
|
|
echo "Deleting HSCI interface $hsci with the HiperSockets $hsdev and the external $ndev"
|
|
|
|
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to turn off learning_sync on $hsdev" >&2
|
|
return 1
|
|
fi
|
|
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
|
|
|
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
|
|
echo "Deleting $hsev MAC $hsdev_mac on $ndev"
|
|
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to delete $hsev MAC $hsdev_mac on $ndev" >&2
|
|
return 1
|
|
fi
|
|
|
|
ip link del $hsci >/dev/null 2>&1
|
|
if [ $? -ne 0 ]; then
|
|
echo "Error: Failed to delete $hsci" >&2
|
|
return 1
|
|
fi
|
|
echo "Successfully deleted device $hsci"
|
|
|
|
return 0
|
|
}
|
|
|
|
##############################################################################
|
|
## Show HSCI
|
|
##############################################################################
|
|
|
|
function list_active {
|
|
hsdev=$1
|
|
local ext=""
|
|
|
|
hsci="$(ip link show dev $hsdev | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
|
|
ext="$(ip link show | grep "master $hsci" | grep --invert-match $hsdev | awk '{print $2}')"
|
|
# remove trailing ':'
|
|
ndev="${ext%:}"
|
|
|
|
check_pnetids
|
|
|
|
printf '%-8s %-16s %-15s %-15s\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
|
|
|
|
return 0
|
|
}
|
|
|
|
function print_header {
|
|
if [ $header -eq 0 ]; then
|
|
echo "HSCI PNET_ID HiperSockets External "
|
|
echo "------------------------------------------------------------"
|
|
fi
|
|
}
|
|
|
|
function list_one {
|
|
local hsnetdev=$1
|
|
|
|
if [ $(bridge -d link show dev $hsnetdev | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
|
print_header
|
|
list_active $hsnetdev
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
function show_hsci {
|
|
if [ $# != 0 ]; then
|
|
echo "hsci: invalid parameters" >&2
|
|
echo "Use 'hsci --help' for more information" >&2
|
|
return 1
|
|
fi
|
|
header=0
|
|
|
|
for hs_net_dev in $(ls -1 /sys/class/net/); do
|
|
list_one $hs_net_dev
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
#==============================================================================
|
|
|
|
function print_version()
|
|
{
|
|
echo "hsci utility: version %S390_TOOLS_VERSION%"
|
|
echo "Copyright IBM Corp. 2020"
|
|
}
|
|
|
|
##############################################################################
|
|
##### Main
|
|
##############################################################################
|
|
prereqs_check
|
|
|
|
args="$(getopt -u -o hv -l help,version -- $*)"
|
|
[ $? -ne 0 ] && exit 2
|
|
set -- $args
|
|
while true; do
|
|
case $1 in
|
|
-v | --version)
|
|
print_version
|
|
exit 0
|
|
;;
|
|
-h | --help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--)
|
|
;;
|
|
add) shift
|
|
add_hsci "$@"
|
|
exit $?
|
|
;;
|
|
del) shift
|
|
del_hsci "$@"
|
|
exit $?
|
|
;;
|
|
show) shift
|
|
show_hsci "$@"
|
|
exit $?
|
|
;;
|
|
*) echo "hsci: Please specify a valid command or option" >&2
|
|
echo "Use 'hsci --help' for more information" >&2
|
|
exit 1
|
|
esac
|
|
shift
|
|
done
|
|
|