From 48cf3b3809f7216a90f79ca95785b688300c993a Mon Sep 17 00:00:00 2001 From: Alexandra Winter Date: Mon, 20 Sep 2021 12:01:29 +0200 Subject: [PATCH] hsci: Compatibility with old kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without kernel commits f7936b7b2663 s390/qeth: Update MACs of LEARNING_SYNC device 4e20e73e631a s390/qeth: Switchdev event handler 60bb1089467d s390/qeth: Register switchdev event handler HSCI cannot be used with multiple MACs, but the single MAC usecase needs to be supported even with old kernel. So manually setting the same single MAC on hsci, HiperSockets and the external interface is still required. The hsci itself is not a bridgeport, so a static forwarding rule in the bridge is also required. It seems cleaner to use the initial MAC of the veth hsci as single static MAC, than the initial MAC of the HiperSockets interface. Even with an updated kernel a single static MAC interface, that is not subject to ageing and re-learning, is beneficial when hsci is used as a single MAC interface. Signed-off-by: Alexandra Winter Reviewed-by: Wenjia Zhang Signed-off-by: Jan Höppner --- hsci/hsci | 86 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/hsci/hsci b/hsci/hsci index 6867d391..cef9bc19 100755 --- a/hsci/hsci +++ b/hsci/hsci @@ -13,7 +13,7 @@ ndev="" hsci="" hscibr="" hscibp="" -hsdev_mac="" +hsci_mac="" hsif_pnetid="" netif_pnetid="" hsci_pnetid="" @@ -184,7 +184,8 @@ function clean_up { ip link del $hsci >/dev/null 2>&1 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 + bridge fdb del $hsci_mac dev $hsdev self local >/dev/null 2>&1 + bridge fdb del $hsci_mac dev $ndev self local >/dev/null 2>&1 ip link del $hscibr >/dev/null 2>&1 } @@ -278,18 +279,6 @@ function add_hsci { # 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 (idempotent) - if [ $(bridge fdb show dev $ndev | grep "$hsdev_mac self permanent" | wc -l) -eq 0 ]; then - 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 - fi ip link set dev $hscibr up >/dev/null 2>&1 if [ $? -ne 0 ]; then @@ -338,11 +327,39 @@ function add_hsci { return 1 fi - # set HS MAC (common MAC) on HSCI as primary MAC (idempotent) - if [ $(bridge fdb show dev $hsci | grep "$hsdev_mac self permanent" | wc -l) -eq 0 ]; then - ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1 + #### Set a static forwarding rule for hsci MAC, so hsci can be used as a + #### single-MAC network interface without being subject to + #### ageing and re-learning + #### Wait for systemd to change the MAC of hsci, if it wants to: + sleep 1 + hsci_mac="$(cat /sys/class/net/$hsci/address)" + #### (idempotent) + if [ $(bridge fdb show dev $hscibp | grep "$hsci_mac master $hscibr static" | wc -l) -eq 0 ]; then + bridge fdb add $hsci_mac dev $hscibp master static if [ $? -ne 0 ]; then - echo "Error: Failed to set HiperSockets MAC (common MAC) on HSCI as primary MAC" >&2 + echo "Error: Failed to set $hsci_mac to $hscibr fdb" >&2 + clean_up + return 1 + fi + fi + + # Bridge-to-device learning will set this MAC on hsdev and ndev. + # Old kernel code doesn't do hsci bridge-to-device learning. + # In this case: Set hsci_mac as local MAC of hsdev and ndev, + # so at least the single-MAC scenario works. + if [ $(bridge fdb show dev $hsdev | grep "$hsci_mac self permanent" | wc -l) -eq 0 ]; then + echo "Warning: $hsci will support only its current static MAC address. Please upgrade your kernel to the latest level." >&2 + bridge fdb add $hsci_mac dev $hsdev self local + if [ $? -ne 0 ]; then + echo "Error: Failed to add $hsci_mac to $hsdev" >&2 + clean_up + return 1 + fi + fi + if [ $(bridge fdb show dev $ndev | grep "$hsci_mac self permanent" | wc -l) -eq 0 ]; then + bridge fdb add $hsci_mac dev $ndev self local + if [ $? -ne 0 ]; then + echo "Error: Failed to add $hsci_mac to $ndev" >&2 clean_up return 1 fi @@ -381,6 +398,7 @@ function del_hsci { echo "Error: $hsci does not exit" >&2 return 1 fi + hsci_mac="$(cat /sys/class/net/$hsci/address)" #### Find hscibp and hscibr hscibp="$(ip -o link show dev $hsci | awk '{print $2}')" @@ -430,7 +448,27 @@ function del_hsci { if [ $? -ne 0 ]; then echo "Error: Failed to delete $hsci" >&2 fi - echo "Successfully deleted device $hsci" + # Bridge-to-device learning will remove learned MACs from hsdev and ndev. + # Old kernel code doesn't do hsci bridge-to-device learning. + # In this case: Remove the hsci_mac that was added during 'add' from + # hsdev and ndev. + if [ "$hsdev" != "" ]; then + if [ $(bridge fdb show dev $hsdev | grep "$hsci_mac self permanent" | wc -l) -ne 0 ]; then + echo "Warning: It seems your kernel does not support all hsci features, please upgrade." >&2 + bridge fdb del $hsci_mac dev $hsdev self local + if [ $? -ne 0 ]; then + echo "Error: Failed to delete $hsci_mac from $hsdev" >&2 + fi + fi + fi + if [ "$ndev" != "" ]; then + if [ $(bridge fdb show dev $ndev | grep "$hsci_mac self permanent" | wc -l) -ne 0 ]; then + bridge fdb del $hsci_mac dev $ndev self local + if [ $? -ne 0 ]; then + echo "Error: Failed to delete $hsci_mac from $ndev" >&2 + fi + fi + fi #### Reset learning_sync if [ "$hsdev" != "" ]; then @@ -439,16 +477,6 @@ function del_hsci { echo "Error: Failed to turn off learning_sync on $hsdev" >&2 fi fi - - if [ "$hsdev" != "" ] && [ "$ndev" != "" ]; then - 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 - fi - fi - #### Delete bridge if [ "$hscibr" != "" ]; then ip link del $hscibr >/dev/null 2>&1