2
\$\begingroup\$

On my Arch Linux system I have created a script that should do the following on system startup:

  • detect all network interfaces
  • check if physical interfaces are up
  • check if bridge interfaces are up
  • determine if physical interfaces have IPv4 addresses and delete them
  • check if physical interfaces have IPv6 addresses
  • delete global IP addresses from physical interfaces
  • delete link local IP addresses from physical interfaces
  • check if wan bridge interface has an IPv4 address
  • check if wan bridge interface has global IPv6 addresses
  • delete global IPv6 addresses from wan bridge interface
  • check if wan bridge interface has link local IPv6 addresses
  • delete link local IPv6 addresses from wan bridge interface
  • check if other bridge interfaces except the lan bridge interface have an IPv4 address
  • delete IPv4 addresses from those interfaces
  • check if other bridge interfaces except the lan bridge
  • interface have IPv6 addresses
  • delete IPv6 addresses from those interfaces
  • check if spezific vm is running
  • start specific vm if it is not running
  • check if this specific vm is now running
  • change network configuration for lan bridge interface to use dhcp
  • restart systemd-networkd to reflect new network configuration for lan bridge interface
  • verify that lan bridge interface got IPv4 and IPv6 addresses
  • start other vms on purpose
  • verify that other vms are running
  • log everything to a log file

and another one to restore the startup network configuration on shutdown.

Due to the long list of tasks especially the first script became very complex and long (over 1500 lines). To make it worse I do not like programming and normally avoid doing this. So my knowledge is on a very basic level. Although the scripts seem to be working I must written most of them in a fit of deliriousness. When I now review them I do not understand most of the stuff I have written there.

So please review the script for any bugs and possible optimisations. They should be as foolproof and general (i.e. the names of the network interfaces should be assigned to variables) as possible.

### uncomment to send all output to vmrun.log file
### save stdout and stderr to file descriptors 3 and 4, then
### redirect them to /var/log/vmrun.log
###
exec 3>&1 4>&2 >/var/log/vmrun.log 2>&1

### declare global variables

# equivalent for DOS pause command
declare -r pausearg="Press any key to continue..."
# naming convention, bridge interfaces should start with br
declare -r bridgeinterfacestart="br"
# lan bridge interface
declare -r lanbr="brlan"
# string variable for IPv4 address of lan bridge interface
declare -r lanbr_ipv4_addr="192.168.3.4"
# wan bridge interface
declare -r wanbr="brwan"
# dmz bridge interface
declare -r dmzbr="brdmz"
# amount of seconds to sleep
declare -r sleeptime=3
# max counter value for loops
declare -r maxcounter=10
# string varibale for vm state shut off when locale is not set or C
declare -r vmstate_shutoff="shut off"
# string varibale for vm state running when locale is not set or C
declare -r vmstate_running="running"
# To handle the state of the vms correctly you need to set the
# variables vmstate_localized_shutoff and vmstate_localized_running in
# the "Global variables" section to the values the command
# "virsh list --all" returns for machines in shut down and running state
# for your locale
# In this script they are set for german language
# string variable for vm state shut off when locale set to german language
declare -r vmstate_shutoff_localized="ausschalten"
# string variable for vm state running when locale set to german language
declare -r vmstate_running_localized="laufend"
# name of first vm
declare -r vm1_name="lede"
# IPv4 address of vm1 for ping
declare -r vm1_ipv4_addr="192.168.3.1"
# boolean variable vor vm status
declare vmstate=0
# string variable for name of startup network config file for openvswitch
# lan bridge interface
declare -r brlan_config="/etc/systemd/network/50-ovs-brlan.network"
# string variable for name of safety copy of network config file for
# openvswitch lan bridge interface
declare -r brlan_config_startup="/etc/systemd/network/50-ovs-brlan.startup"
# string variable for name of network config file for openvswitch lan
# bridge interface to use after virtual machine vm1_name started up
declare -r brlan_config_aftervm="/etc/systemd/network/50-ovs-brlan.aftervm"
# string variable for md5 checksumfile for network config files for
# openvswitch lan bridge interface
declare -r brlan_configs_md5="/opt/vmchecks/50-ovs-brlan.md5"
# string variable for sha checksumfile for network config files for
# openvswitch lan bridge interface
declare -r brlan_configs_sha="/opt/vmchecks/50-ovs-brlan.sha"
# array with variable names of network config files
declare -r -a arr_brlan_config_files=(brlan_config brlan_config_startup brlan_config_aftervm)
# array with variable names of checksum files
declare -r -a arr_checksum_brlan_config_files=(brlan_configs_md5 brlan_configs_sha)
# array with the lines from the checksum files
declare -a arr_checksum_lines
# string variable for config file name
declare conf_file=""
# string variable for checksum file name
declare checksum_file=""
# string variable for checksum filename from array arr_checksum_lines
declare checksum_filename_from_arr
# string variable for saving current IFS
declare IFS_SAVE=""
# array with needed external programs
declare -a arr_ext_programs_needed=(md5sum sha512sum ip awk sed lshw grep ethtool systemctl cp diff virsh sleep date cat sysctl cut)
# array for list of all interfaces
declare -a arr_iface_all=()
# array for list of physical interfaces
declare -a arr_iface_phy=()
# array for list of virtual interfaces
declare -a arr_iface_virt=()
# array for list of virtual bridge interfaces
declare -a arr_iface_virt_bridge=()
# array for list of virtual openvswitch bridge interfaces
declare -a arr_iface_virt_ovsbridge=()
# array for list of virtual nonbridge interfaces
declare -a arr_iface_virt_nonbridge=()
# array for interfaces with ip address
declare -a arr_iface_withip=()


### declare functions

# function to emulate DOS pause command
declare -f func_pause
# function to check if all needed external programs are installed
declare -f func_needed_ext_progs
# function to get an array with all known interfaces
declare -f func_arr_iface_all
# function to get an array with all physical interfaces
declare -f func_arr_iface_phy
# function to get an array with all virtual interfaces
declare -f func_arr_iface_virt
# function to build array with virtual bridge interfaces
declare -f func_arr_iface_virt_bridge
# function to build array with virtual openvswitch bridge interfaces
declare -f func_arr_iface_virt_ovsbridge
# function to build array with virtual nonbridge interfaces
declare -f func_arr_iface_virt_nonbridge
# function to test if all physical interfaces are connected
declare -f func_iface_phy_carrier
# function to check if an interface is up
declare -f func_iface_up
# function to check if an interface has an IPv4 address
declare -f func_iface_ipv4
# function to check if an interface has an IPv6 address
declare -f func_iface_ipv6
# function to delete IPv4 addresses from an interface
declare -f func_iface_del_ipv4
# function to delete IPv6 addresses not starting with fe80: from an 
# interface
declare -f func_iface_del_ipv6
# function to delete IPv6 addresses starting with fe80: from an interface
declare -f func_iface_del_ipv6_fe80
# function to test if IPv4 addresses were deleted from an interface
declare -f func_iface_del_test_ipv4
# function to test if all IPv6 addresses not starting with fe80: were 
# deleted from an interface
declare -f func_iface_del_test_ipv6
# function to disable IPv6 on physical interfaces
declare -f func_iface_ipv6_disable
# function to test if IPv6 is disabled on an inteface
declare -f func_iface_ipv6_disabled_test
# function to get state of a virtual machine
declare -f func_vm_state
# function to start a virtual machine
declare -f func_vm_start
# function to verify that a virtual machine is running
declare -f func_vm_start_verify
# function to wait for a virtual machine to fully start up
declare -f func_vm_start_completed
# function to check if file exists
declare -f func_file_exists

###  name: func_pause
###  function emulate the DOS pause command
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_pause
{
    read -n1 -r -p "$*"
}

###  name: func_needed_ext_progs
###  function to check if all needed external programs are installed
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_needed_ext_progs
{
    for ((i=0; i<${#arr_ext_programs_needed[@]}; i++))
    do
        if ! command -v "${arr_ext_programs_needed[i]}" &>/dev/null
        then
            echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t I require ${arr_ext_programs_needed[i]} but could not find it. Aborting."
            exit 1
        fi
    done
}

###  name: func_arr_iface_all
###  function to get an array with all known interfaces excluding
###  loopback (lo) and ovs-system interface
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_arr_iface_all
{
#define local variables
# temporary array for interfaces list
    local -a arr_iface_tmp=()
# counter variable
    local -i i=0
# length of tremporary array with all known interfaces
    local -i arr_iface_tmp_length=0
# get list of existing interfaces
    arr_iface_tmp=( "$( ip -o link | awk '{ print $2 }' | sed 's/.$//' )" )
# get length of array
    arr_iface_tmp_length=${#arr_iface_tmp[@]}
# delete loopback (lo) interface and ovs-system interface from array
# and build final array without them
    for ((i=0; i<arr_iface_tmp_length; i++))
    do
        if [ "${arr_iface_tmp[i]}" == "lo" ] || [ "${arr_iface_tmp[i]}" == "ovs-system" ]
        then
            unset 'arr_iface_tmp[i]'
        fi
    done
    IFS_SAVE=$IFS
    IFS=$'\n'
    read -d '' -r -a arr_iface_all <<< "${arr_iface_tmp[@]}"
    IFS=$IFS_SAVE
}

###  name: func_arr_iface_phy
###  function to get an array with all physical interfaces
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_arr_iface_phy
{
    local -a arr_tmp
# get list of physical interfaces identified by lshw -c network -businfo 
# assuming only physical interfaces have a non empty businfo field
    arr_tmp="$( lshw -c network -businfo | grep '^[^ B=]' | awk '{ print $2 }' )"
    IFS_SAVE=$IFS
    IFS=$'\n'
    read -d '' -r -a arr_iface_phy <<< "${arr_tmp[@]}"
    IFS=$IFS_SAVE
}

###  name: func_arr_iface_virt
###  function to get an array with all virtual interfaces by deleting
###  all physical interfaces from array of all known interfaces
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_arr_iface_virt
{
    local -a arr_iface_tmp=("${arr_iface_all[@]}")
    local arr_iface_tmp_length=${#arr_iface_tmp[@]}
    local arr_iface_phy_length=${#arr_iface_phy[@]}
    local -i i=0
    local -i j=0
    for ((i=0; i<arr_iface_tmp_length; i++))
    do
        for ((j=0; j<arr_iface_phy_length; j++))
        do
            if [ "${arr_iface_tmp[i]}" == "${arr_iface_phy[j]}" ]
            then
                unset 'arr_iface_tmp[i]'
            fi
        done
    done
    arr_iface_virt=("${arr_iface_tmp[@]}")
}

###  name: func_arr_iface_virt_bridge
###  function to get an array with all virtual bridge interfaces by
###  deleting all virtual non bridge interfaces from array of all
###  virtual interfaces
###  @param 
###  no arguments required
###  @return
###  returns nothing
function func_arr_iface_virt_bridge
{
    local -a arr_iface_virt_bridge_tmp=("${arr_iface_virt[@]}")
    local arr_iface_virt_bridge_tmp_length=${#arr_iface_virt_bridge_tmp[@]}
    local -i i=0

# extract bridge interfaces from virtual interfaces
    for ((i=0; i<arr_iface_virt_bridge_tmp_length; i++))
    do
        if [[ "${arr_iface_virt_bridge_tmp[i]}" != $bridgeinterfacestart*  ]]
        then
            unset 'arr_iface_virt_bridge_tmp[i]'
        fi
    done
    arr_iface_virt_bridge=("${arr_iface_virt_bridge_tmp[@]}")
}

###  name: func_arr_iface_virt_nonbridge
###  function to get an array with all virtual nonbridge interfaces
###  by deleting all virtual bridge interfaces from array of all
###  virtual interfaces
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_arr_iface_virt_nonbridge
{
    local -a arr_iface_virt_nonbridge_tmp=("${arr_iface_virt[@]}")
    local arr_iface_virt_nonbridge_tmp_length=${#arr_iface_virt_nonbridge_tmp[@]}
    local -i i=0

# extract nonbridge interfaces from virtual interfaces
    for ((i=0; i<arr_iface_virt_nonbridge_tmp_length; i++))
    do
        if [[ "${arr_iface_virt_nonbridge_tmp[i]}" == $bridgeinterfacestart*  ]]
        then
            unset 'arr_iface_virt_nonbridge_tmp[i]'
        fi
    done
    arr_iface_virt_nonbridge=("${arr_iface_virt_nonbridge_tmp[@]}")
}

###  name: func_arr_iface_virt_ovsbridge
###  function to get an array with all virtual openvswitch bridge
###  interfaces by deleting all non openvswitch virtual bridge
###  interfaces from array of all virtual bridge interfaces
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_arr_iface_virt_ovsbridge
{
    local -a arr_iface_virt_ovsbridge_tmp=("${arr_iface_virt_bridge[@]}")
    local arr_iface_virt_ovsbridge_tmp_length=${#arr_iface_virt_ovsbridge_tmp[@]}
    local -i i=0

# build list of virtual openvswitch bridge interfaces
    for ((i=0; i<arr_iface_virt_ovsbridge_tmp_length; i++))
    do
        if ethtool -i "${arr_iface_virt_ovsbridge_tmp[i]}" | grep -q openvswitch
        then
            unset 'arr_iface_virt_ovsbridge_tmp[i]'
        fi
    done
    arr_iface_virt_ovsbridge=("${arr_iface_virt_ovsbridge_tmp[@]}")
}

###  name: func_iface_phy_carrier
###  function to test if all physical interfaces are connected
###  @param
###  no arguments required
###  @return
###  returns nothing
function func_iface_phy_carrier
{
    local loc_iface
    local -i loc_maxcount
    local -i i=0

    loc_maxcount=$((maxcounter-5))
    for loc_iface in "${arr_iface_phy[@]}"
    do
        if ip link show "$loc_iface" | grep -q '\bNO-CARRIER\b'
        then
            for ((i=0; i<=loc_maxcount; i++))
            do
                sleep "$sleeptime"s
                if ip link show "$loc_iface" | grep -q '\bNO-CARRIER\b'
                then
                    break
                fi
            done
            if [[ $i -gt $loc_maxcount ]]
            then
                echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t I require physical interface ${loc_iface} connected but it's not. Aborting."
                exit 1
            fi
        else
            echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Physical interface ${loc_iface} is connected. OK."
        fi
    done
}

###  name: func_iface_up
###  function to test if an interface is up
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_up
{
    if ! ip link show "$1" | grep -q '\bUP\b'
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t I require interface ${1} is UP but it's not. Aborting."
        exit 1
    else 
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Interface ${1} is UP. OK."
    fi
}

###  name: func_iface_ipv4
###  function to test if an interface has an IPv4 address
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_ipv4
{
    if [[ "$(ip -4 addr show "$1")" ]]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Interface $1 has an IPv4 address."
        arr_iface_withip+=( "$1" )
    fi
}

###  name: func_iface_del_ipv4
###  function to delete IPv4 address from an interface
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_del_ipv4
{
    local -a loc_arr_addr=()
    local addr

    loc_arr_addr=("$(ip -4 addr show "$1" | grep '\binet\b' | awk '{ print $2 }')")
    for addr in "${loc_arr_addr[@]}"
    do
        ip addr del "$addr" dev "$1"
    done
}

###  name: func_iface_del__test_ipv4
###  function to test if IPv4 addresses were deleted from interface
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_del_test_ipv4
{
    if [[ -z $(ip -4 addr show "$1" | grep '\binet\b' | awk '{ print $2 }') ]]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv4 Addresses successfully deleted from $1."
    else
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv4 Addresses not deleted from $1. Aborting."
        exit 1
    fi
}

###  name: func_iface_ipv6
###  function to test if an interface has an IPv6 address
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_ipv6
{
    if [ "$(ip -6 addr show "$1")" ]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Interface $1 has an IPv6 address."
        arr_iface_withip+=( "$1" )
    fi
}

###  name: func_iface_del_ipv6
###  function to delete IPv6 addresses except the ones starting with
###  fe80: from an interface
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_del_ipv6
{
    local -a loc_arr_addr=()
    local addr

    loc_arr_addr=("$(ip -6 addr show "$1" | grep '\binet6\b' | awk '{ print $2 }')")
    for addr in "${loc_arr_addr[@]}"
    do
        if [[ $addr != fe80:* ]]
        then
            ip -6 addr del "$addr" dev "$1"
        else
            echo -e "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv6 address on interface $1 starts with fe80:. I will not delete it."
        fi
    done
}

###  name: func_iface_del_ipv6_fe80
###  function to delete IPv6 addresses starting with fe80: from an
###  interface
###  @param
###  interface name required
###  @return
###  returns nothing
function func_iface_del_ipv6_fe80
{
    local -a loc_arr_addr=()
    local addr

    loc_arr_addr=("$(ip -6 addr show "$1" | grep '\binet6\b' | awk '{ print $2 }')")
    for addr in "${loc_arr_addr[@]}"
    do
        if [[ $addr = fe80:* ]]
        then
            ip -6 addr del "$addr" dev "$1"
        else
            echo -e "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv6 address on interface $1 does not start with fe80:. I will not delete it."
        fi
    done
}

###  name: func_iface_del__test_ipv6                                 ###
###  function to test if all IPv6 addresses not starting with fe80:  ###
###  were deleted from interface
###  @param                                                          ###
###  interface name required
###  @return                                                         ###
###  returns nothing
function func_iface_del_test_ipv6
{
    local -a loc_arr_addr=()
    local -a loc_arr_addr_tmp=()
    local addr=""
    local -i loc_arr_addr_tmp_length=0
    local -i i=0

    loc_arr_addr_tmp=("$(ip -6 addr show "$1" | grep '\binet6\b' | awk '{ print $2 }')")
    loc_arr_addr_tmp_length=${#loc_arr_addr_tmp[@]}
    for ((i=0; i<loc_arr_addr_tmp_length; i++))
    do
        if [[ "${loc_arr_addr_tmp[i]}" == fe80:* ]]
        then
            unset 'loc_arr_addr_tmp[i]'
        fi
    done
    loc_arr_addr=("${loc_arr_addr_tmp[@]}")
    if [ ${#loc_arr_addr[@]} != 0 ]
    then
        echo -e "$(date '+%Y-%m-%d %H:%M:%S')\\t Not all IPv6 addresses not starting with fe80: were deleted from interface $1. Aborting."
        exit 1
    else
        echo -e "$(date '+%Y-%m-%d %H:%M:%S')\\t All IPv6 addresses not starting with fe80: were deleted from interface $1. OK."
    fi
}

########################################################################
###                                                                  ###
###  name: func_iface_del__test_ipv6_fe80                            ###
###  function to test if all IPv6 addresses starting with fe80: were ###
###  deleted from interface                                          ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_iface_del_test_ipv6_fe80
{
    local -a loc_arr_addr=()
    local -a loc_arr_addr_tmp=()
    local addr=""
    local -i loc_arr_addr_tmp_length=0
    local -i i=0

    loc_arr_addr_tmp=("$(ip -6 addr show "$1" | grep '\binet6\b' | awk '{ print $2 }')")
    loc_arr_addr_tmp_length=${#loc_arr_addr_tmp[@]}
    for ((i=0; i<loc_arr_addr_tmp_length; i++))
    do
        if [[ "${loc_arr_addr_tmp[i]}" != fe80:* ]]
        then
            unset 'loc_arr_addr_tmp[i]'
        fi
    done
    loc_arr_addr=("${loc_arr_addr_tmp[@]}")
    if [ ${#loc_arr_addr[@]} != 0 ]
    then
        echo -e "$(date '+%Y-%m-%d %H:%M:%S')\\t Not all IPv6 addresses starting with fe80: were deleted from interface $1. Aborting."
        exit 1
    else
        echo -e "$(date '+%Y-%m-%d %H:%M:%S')\\t All IPv6 addresses starting with fe80: were deleted from interface $1. OK."
    fi
}

########################################################################
###                                                                  ###
###  name: func_iface_ipv6_disable                                   ###
###  function to disable IPv6 on an interface                        ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_iface_ipv6_disable
{
    sysctl -w net.ipv6.conf."$1".disable_ipv6=1
}

########################################################################
###                                                                  ###
###  name: func_iface_ipv6_disabled_test                             ###
###  function to test if IPv6 is disabled on an interface            ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_iface_ipv6_disabled_test
{
    if [ "$( cat /proc/sys/net/ipv6/conf/"$1"/disable_ipv6 )" -eq 1 ]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv6 is disabled on $1."
    else
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv6 is not disabled on $1. Aborting"
        exit 1
    fi
}

########################################################################
###                                                                  ###
###  name: func_vm_state                                             ###
###  function to get status of a virtual machine                     ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_vm_state
{
    local loc_vmstatus
    local -i i=1

    unset vmstate
    for ((i=1; i<=maxcounter; i++))
    do
        loc_vmstatus=$( virsh list --all | grep "$1" | awk '{print $3}' )
        case "$loc_vmstatus" in
            "$vmstate_shutoff"|"$vmstate_shutoff_localized")
                vmstate=0
                break
                ;;
            "$vmstate_running"|"$vmstate_running_localized")
                vmstate=1
                break
                ;;
            *)
                vmstate=2
                ;;
        esac
        sleep "$sleeptime"s
    done
    if [ $vmstate -eq 2 ]
    then

        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Could not get status of vm $1 after "$((maxcounter * sleeptime))"s waiting."
    fi
}

########################################################################
###                                                                  ###
###  name: func_vm_start                                             ###
###  function to get status of a virtual machine                     ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_vm_start
{
    local loc_vmstatus
    local -i i=0

    virsh start "$1" &>/dev/null
    for ((i=0; i<=maxcounter; i++))
    do
        sleep "$sleeptime"s
        loc_vmstatus=$( virsh list --all | grep "$1" | awk '{print $3}' )
        if [ "$loc_vmstatus" == "$vmstate_running" ] || [ "$loc_vmstatus" == "$vmstate_running_localized" ]
        then
            break
        fi
    done
}

########################################################################
###                                                                  ###
###  name: func_vm_start_verify                                      ###
###  function to get status of a virtual machine                     ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_vm_start_verify
{
    if [ $vmstate -eq 1 ]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machine $1 is running."
    else
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machine $1 is not properly running"
    fi
}

########################################################################
###                                                                  ###
###  name: func_vm_start_completed                                   ###
###  function to wait for a virtual machine to fully start up        ###
###  assuming it is when it can be pinged                            ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###  vm IPv4 address required                                        ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_vm_start_completed
{
    local loc_ping_success=0
    local -i maxcount=maxcounter+5
    for ((i=0; i<=maxcount; i++))
    do
        if ping -4 -w1 -c1 "$2" &>/dev/null
        then
            loc_ping_success=1
            echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start up of virtual machine $1 completed."
            break
        else
            loc_ping_success=0
            sleep "$sleeptime"s
        fi
    done
    if [ $loc_ping_success -eq 0 ]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start up of virtual machine $1 did not complete after "$((maxcount * sleeptime))"s. Aborting."
        exit 1
    fi
}

########################################################################
###                                                                  ###
###  name: func_file_exists                                          ###
###  function to check if file exists                                ###    
###                                                                  ###
###  @param                                                          ###
###  filename with absolute path                                     ###
###                                                                  ###
###  @return                                                         ###
###  returns nothing                                                 ###
###                                                                  ###
########################################################################
function func_file_exists
{
    if ! [ -f "$1" ]
    then
        echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t $1 file does not exist. Aborting."
        exit 1
    else
        echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t $1 file exists."
    fi
}

########################################################################
### main program                                                     ###
### requires no arguments                                            ###
########################################################################
# check if all needed external programs are installed
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if all needed external programms are installed."
func_needed_ext_progs
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if all needed external programms are installed finished."
# get list of existing interfaces in array variable arr_iface_all
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Get list of all known networkinterfaces."
func_arr_iface_all
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Get list of all known networkinterfaces finished."
# get list of physical interfaces in array variable arr_iface_phy
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Get list of all physical networkinterfaces."
func_arr_iface_phy
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Get list of all physical networkinterfaces finished."
# check if all physical interfaces have a carrier, required
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if physical interfaces have a carrier."
func_iface_phy_carrier
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if physical interfaces have a carrier finished."

# build list of virtual interfaces
func_arr_iface_virt

# build list of virtual bridge interfaces
func_arr_iface_virt_bridge

# build list of virtual non bridge iterfaces
func_arr_iface_virt_nonbridge

# build list of virtual openvswitch bridge interfaces
func_arr_iface_virt_ovsbridge

# check if all physical interfaces are up, required
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if physical interfaces are up."
for iface in "${arr_iface_phy[@]}"
do
    func_iface_up "$iface"
done
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if physical interfaces are up finished."
unset iface

# check if all openvswitch bridge interfaces are up, required
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if virtual openvswitch bridge interfaces are up."
for iface in "${arr_iface_virt_ovsbridge[@]}"
do
    func_iface_up "$iface"
done
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if virtual openvswitch bridge interfaces are up finished."
unset iface

# in this System physical interfaces should not have an IPv4 address
# check if physical interfaces have an IPv4 address
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if physical interfaces have an IPv4 address."
arr_iface_withip=()
for iface in "${arr_iface_phy[@]}"
do
    func_iface_ipv4 "$iface"
done
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if physical interfaces have an IPv4 address finished."
# deleting IPv4 addresses from physical interfaces
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Some physical interfaces have an IPv4 address, deleting it"
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv4 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv4 addresses from physical interfaces finished"
# test if IPv4 adresses are deleted
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv4 addresses, from physical interfaces are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv4 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv4 addresses, from physical interfaces are deleted finished."

# in this System the openvswitch wan bridge interface should not have an IPv4 address
# check if openvswitch wan bridge interface has an IPv4 address
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if openvswitch wan bridge has an IPv4 address."
arr_iface_withip=()
func_iface_ipv4 "$wanbr"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch wan bridge has an IPv4 address finished."
# deleting IPv4 addresses from openvswitch wan bridge interface
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch wan bridge interface has an IPv4 address, deleting it"
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv4 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv4 addresses from openvswitch wan bridge interface finished."
# test if IPv4 adresses are deleted
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if IPv4 addresses from openvswitch wan bridge are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv4 "$iface"
    done
fi
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv4 addresses from openvswitch wan bridge are deleted finished."

# in this System the openvswitch dmz bridge interface should not have an IPv4 address
# check if openvswitch dmz bridge interface has an IPv4 address
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if openvswitch dmz bridge has an IPv4 address."
arr_iface_withip=()
func_iface_ipv4 "$dmzbr"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch dmz bridge has an IPv4 address finished."
# deleting IPv4 addresses from openvswitch dmz bridge interface
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch dmz bridge interface has an IPv4 address, deleting it"
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv4 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv4 addresses from openvswitch dmz bridge interface finished."
# test if IPv4 adresses are deleted
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if IPv4 addresses from openvswitch dmz bridge are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv4 "$iface"
    done
fi
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv4 addresses from openvswitch dmz bridge are deleted finished."
arr_iface_withip=()

# in this System physical interfaces should not have an IPv6 address
# check if physical interfaces have an IPv6 address except for the ones
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if physical interfaces have an IPv6 address."
arr_iface_withip=()
for iface in "${arr_iface_phy[@]}"
do
    func_iface_ipv6 "$iface"
done
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if physical interfaces have an IPv6 address finished."
# delete IPv6 addresses from physical interfaces except for the ones 
# starting with "fe80:"
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Some physical interfaces have IPv6 addresses, deleting them if they start not with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6 "$iface"
    done
fi
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses not starting with fe80: from physical interfaces finished."
# test if IPv6 adresses except the ones starting with fe80: are deleted
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from physical interfaces are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6 "$iface"
    done
fi
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from physical interfaces not starting with fe80: are deleted finished."
# delete IPv6 addresses from physical interfaces starting with "fe80:"
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Some physical interfaces have IPv6 addresses, deleting them if they start with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6_fe80 "$iface"
    done
fi
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses starting with fe80: from physical interfaces finished."
# test if IPv6 adresses starting with fe80: are deleted
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from physical interfaces are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6_fe80 "$iface"
    done
fi
unset iface
arr_iface_withip=()
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from physical interfaces starting with fe80: are deleted finished."
# disabling IPv6 on physical interfaces to make sure that no communication via IPv6 is possible
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start disabling IPv6 on physical interfaces"
#for iface in "${arr_iface_phy[@]}"
#do
#   func_iface_ipv6_disable "$iface"
#done
#unset iface
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Disabling IPv6 on physical interfaces finished."
# test if IPv6 on physical interfaces is disabled
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 on physical interfaces is disabled"
#for iface in "${arr_iface_phy[@]}"
#do
#   func_iface_ipv6_disabled_test "$iface"
#done
#unset iface
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 on physical interfaces is disabled finished."


# in this System the openvswitch wan bridge interface should not have an
# IPv6 address
# check if the openvswitch wan bridge interface have an IPv6 address 
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if the openvswitch wan bridge interface has an IPv6 address."
arr_iface_withip=()
func_iface_ipv6 "$wanbr"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch wan bridge have IPv6 addresses finished."
# delete IPv6 addresses from the openvswitch wan bridge interface except
# for the ones starting with "fe80:"
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t The openvswitch wan bridge interface has IPv6 addresses, deleting them if they start not with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses from openvswitch wan bridge interface finished."
# test if IPv6 adresses except the ones starting with fe80: are deleted
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from openvswitch wan bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses not starting with fe80: from openvswitch wan bridge interface are deleted finished."
# delete IPv6 addresses from the openvswitch wan bridge interface starting with "fe80:"
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t The openvswitch wan bridge interface has IPv6 addresses, deleting them if they start with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6_fe80 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses starting with fe80: from openvswitch wan bridge interface finished."
# test if IPv6 adresses except the ones starting with fe80: are deleted
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses starting with fe80: from openvswitch wan bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6_fe80 "$iface"
    done
fi
unset iface
arr_iface_withip=()
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses starting with fe80: from openvswitch wan bridge interface are deleted finished."
# disabling IPv6 on openvswitch wan interfaces to make sure that no communication via IPv6 is possible
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start disabling IPv6 on openvswitch wan interface"
#func_iface_ipv6_disable "$wanbr"
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Disabling IPv6 on openvswitch wan interface finished."
# test if IPv6 on openvswitch wan interface is disabled
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 on openvswitch wan interface is disabled"
#func_iface_ipv6_disabled_test "$wanbr"
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 on openvswitch wan interface is disabled finished."

# in this System the openvswitch dmz bridge interface should not have an
# IPv6 address
# check if the openvswitch dmz bridge interface have an IPv6 address 
# except for the ones starting with "fe80:"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if the openvswitch dmz bridge interface has an IPv6 address."
arr_iface_withip=()
func_iface_ipv6 "$dmzbr"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch dmz bridge has IPv6 addresses finished."
# delete IPv6 addresses from the openvswitch dmz bridge interface except
# for the ones starting with "fe80:"
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses not starting with fe80: from openvswitch dmz bridge interface."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t The openvswitch dmz bridge interface has IPv6 addresses, deleting them if they start not with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses starting with fe80: from openvswitch dmz bridge interface finished."
# test if IPv6 adresses except the ones starting with fe80: are deleted
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses not starting with fe80: from openvswitch dmz bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6 "$iface"
    done
fi
unset iface
arr_iface_withip=()
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses not starting with fe80: from openvswitch dmz bridge interface are deleted finished."
# delete IPv6 addresses from the openvswitch dmz bridge interface starting
#  with "fe80:"
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses starting with fe80: from openvswitch dmz bridge interface."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t The openvswitch dmz bridge interface has IPv6 addresses, deleting them if they start with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6_fe80 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses starting with fe80: from openvswitch dmz bridge interface finished."
# test if IPv6 adresses starting with fe80: are deleted from openvswitch dmz bridge interface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses starting with fe80: from openvswitch dmz bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6_fe80 "$iface"
    done
fi
unset iface
arr_iface_withip=()
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses starting with fe80: from openvswitch dmz bridge interface are deleted finished."
arr_iface_withip=()
# disabling IPv6 on openvswitch dmz interfaces to make sure that no communication via IPv6 is possible
# echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start disabling IPv6 on openvswitch dmz interface"
# func_iface_ipv6_disable "$dmzbr"
# echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Disabling IPv6 on openvswitch dmz interface finished."
# test if IPv6 on openvswitch dmz interface is disabled
#echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 on openvswitch dmz interface is disabled"
# func_iface_ipv6_disabled_test "$dmzbr"
# echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 on openvswitch dmz interface is disabled finished."

# test if virtual machine vm1_name is running and start it if not
# get status of virtual machine vm1_name
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Get status of virtual machine $vm1_name."
func_vm_state "$vm1_name"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Getting status of virtual machine $vm1_name finished. State is $vmstate."
# starting virtual machine vm1_name if not running, do nothing if already running
# aborting script if not in running or shut down state
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Starting virtual machine $vm1_name if not running and in a state I can handle."
case $vmstate in
    0)
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machine $vm1_name is not running, starting it."
        func_vm_start "$vm1_name"
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machine $vm1_name started."
        ;;
    1)
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machin $vm1_name is already running."
        ;;
    2)
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machine vm1_name is in a status I cannot handle. Aborting."
        exit 1
        ;;
    *)
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Something in the function to get the state of the virtual machine $1 went wrong. Aborting."
        exit 1
        ;;
esac
unset vmstate
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Starting of virtual machine $vm1_name finished."
#verifying that virtual machine vm1_name is running
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Verifying that virtual machine $vm1_name is running."
func_vm_state "$vm1_name"
func_vm_start_verify "$vm1_name"
if [ $vmstate -ne 1 ]
then
    echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Virtual machine $vm1_name is not running. Aborting."
    exit 1
fi  
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Verifying that virtual machine $vm1_name is running finished."
# wait for virtual machine vm1_name to fully startup
if [ $vmstate -eq 1 ]
then
    echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Wait for virtual machine $vm1_name to fully start up."
    func_vm_start_completed "$vm1_name" "$vm1_ipv4_addr"
fi
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Wait for virtual machine $vm1_name to fully start up finished."
# now the the virtual machine vm1_name is running delete all IPv4 and
# IPv6 addresses from openvswitch lan bridge interface and get new ones
# via dhcp from virtual machine vm1_name
# check if openvswitch lan bridge interface has an IPv4 address
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if openvswitch lan bridge has an IPv4 address."
arr_iface_withip=()
func_iface_ipv4 "$lanbr"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch lan bridge has an IPv4 address finished."
# deleting IPv4 addresses from openvswitch lan bridge interface
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch lan bridge interface has an IPv4 address, deleting it"
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv4 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv4 addresses from openvswitch lan bridge interface finished."
# test if IPv4 adresses are deleted
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if IPv4 addresses from openvswitch lan bridge are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv4 "$iface"
    done
fi
unset iface
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv4 addresses from openvswitch lan bridge are deleted finished."
arr_iface_withip=()
# check if the openvswitch lan bridge interface have an IPv6 address 
# except for the ones starting with "fe80:"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if the openvswitch lan bridge interface has an IPv6 address."
arr_iface_withip=()
func_iface_ipv6 "$lanbr"
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch lan bridge has IPv6 addresses finished."
# delete IPv6 addresses from the openvswitch lan bridge interface except
# except for the ones starting with "fe80:"
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses from openvswitch lan bridge interface finished."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t The openvswitch lan bridge interface has IPv6 addresses, deleting them if they start not with fe80:."
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_ipv6 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Deleting IPv6 addresses from openvswitch lan bridge interface finished."
# test if IPv6 adresses except the ones starting with fe80: are deleted
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from openvswitch lan bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    for iface in "${arr_iface_withip[@]}"
    do
        func_iface_del_test_ipv6 "$iface"
    done
fi
unset iface
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if IPv6 addresses from openvswitch lan bridge interface are deleted finished."
arr_iface_withip=()


# replacing current network config file with the one for use after vm vm1_name is running
# checking if the files exists
# check if needed files exist
# check if needed network config files exist 
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Check if network config files exist."
conf_file=""
for conf_file in "${arr_brlan_config_files[@]}"
do
    func_file_exists "${!conf_file}"
done
conf_file=""
# check if needed checksum files exist
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Check if checksum files for network config files exist."
checksum_file=""
for checksum_file in "${arr_checksum_brlan_config_files[@]}"
do
    func_file_exists "${!checksum_file}"
done
checksum_file=""
#check integrity of files against the checksum files
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Check integrity of network config files against the checksum files."
checksum_file=""
conf_file=""
for checksum_file in "${arr_checksum_brlan_config_files[@]}"
do
    IFS_SAVE=$IFS
    IFS=$'\n'
    read -d '' -r -a arr_checksum < "${!checksum_file}"
    IFS=$IFS_SAVE
    for arr_checksum_lines in "${arr_checksum[@]}"
    do
        checksum_filename_from_arr="$(echo "$arr_checksum_lines" | awk '{print $2}')"
        if [ "${!checksum_file:(-4)}" == .md5 ]
        then
            if [ "$(md5sum "$checksum_filename_from_arr" | awk '{print $1}')" == "$(echo "$arr_checksum_lines" | awk '{print $1}')" ]
            then
                echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t $checksum_filename_from_arr matches md5 checksum stored in ${!checksum_file}."
            else
                echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t $checksum_filename_from_arr does not match md5 checksum stored in ${!checksum_file}. Aborting."
                exit 1
            fi
        fi
        if [ "${!checksum_file:(-4)}" == .sha ]
        then
            if [ "$(sha512sum "$checksum_filename_from_arr" | awk '{print $1}')" == "$(echo "$arr_checksum_lines" | awk '{print $1}')" ]
            then
                echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t $checksum_filename_from_arr matches sha 512 checksum stored in ${!checksum_file}."
            else
                echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t $checksum_filename_from_arr does not match sha 512 checksum stored in ${!checksum_file}. Aborting."
                exit 1
            fi
        fi

    done
done
conf_file=""
checksum_file=""
# copy network config file for openvswitch lan bridge interface for run
# after virtual machine vm1_name startup but only if it differs from
# current network config file and startup network config file and
# current network config file equals startup network config file
if ! diff -q "$brlan_config" "$brlan_config_aftervm" >/dev/null
then
    if ! diff -q "$brlan_config_aftervm" "$brlan_config_startup" >/dev/null
    then
        if diff -q "$brlan_config" "$brlan_config_startup"
        then
            cp -f "$brlan_config_aftervm" "$brlan_config"
        else
            echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Network config file for use at system start differ from current network config file. You are in trouble. Aborting."
            exit 1
        fi
    else
        echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Network config file for use after starting virtual machine does not differ from startup network config file. You are in trouble. Aborting."
        exit 1
    fi
else
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Network config file for use after starting virtual machine does not differ from current network config file. You are in trouble. Aborting."
    exit 1
fi
# verifying that network config file was successful copied
if diff -q "$brlan_config" "$brlan_config_aftervm" >/dev/null
then
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Network config file was successful copied."
else
    echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Network config file was not successful copied. Aborting."
    exit 1
fi

# Restarting systemd-networkd with new config file
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Restarting systemd-networkd."
systemctl restart systemd-networkd
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Restarting systemd-networkd finished."

# check if openvswitch lan bridge interface has an IPv4 address
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Start test if openvswitch lan bridge has an IPv4 address."
arr_iface_withip=()
if [ ${#arr_iface_withip[@]} -eq 0 ]
then
    for ((i=1; i<=maxcounter; i++))
    do
        func_iface_ipv4 "$lanbr"
        if [ ${#arr_iface_withip[@]} -eq 0 ]
        then
            sleep "$sleeptime"s
        else
            break
        fi
    done    
fi
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch lan bridge interface did not get an IPv4 address after"$((maxcounter * sleeptime))"s waiting."
if [ ${#arr_iface_withip[@]} -eq 0 ]
then
    echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch lan bridge interface does not have an IPv4 address assinging one for emergency"
    ip addr add $lanbr_ipv4_addr/24 dev $lanbr
# check if openvswitch lan bridge interface now has an IPv4 address
    if [[ $(ip -4 addr show $lanbr | grep inet | awk '{print $2}' | cut -f1 -d"/") == "$lanbr_ipv4_addr" ]]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch lan bridge interface now has an emergency IPv4 address. Aborting."
        exit 1
    else
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Openvswitch lan bridge interface did not accept the emergency IPv4 address. You are in serious trouble. Aborting."
        exit 1
    fi
fi
echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Test if openvswitch lan bridge has an IPv4 address finished."
# check if openvswitch lan bridge interface equals $lanbr_ipv4_addr
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    if [[ $(ip -4 addr show $lanbr | grep inet | awk '{print $2}' | cut -f1 -d"/") == "$lanbr_ipv4_addr" ]]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Assigned IPv4 address for openvswitch lan bridge interface is correct"
    else
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Assigned IPv4 address for openvswitch lan bridge interface is not correct. Aborting."
        exit 1
    fi
fi
# check if openvswitch lan bridge interface IPv4 address was assigned via DHCP
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    if [[ $(ip -4 addr show $lanbr | grep inet | awk '{print $7}') == "dynamic" ]]
    then
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv4 address of openvswitch lan bridge interface was assigend via DHCP"
    else
        echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t IPv4 address of openvswitch lan bridge interface was not assigend via DHCP"
    fi
fi
arr_iface_withip=()
# final message
echo -e <&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t Script finished"

#func_pause "$pausearg"

# restoring original output and closing created file descriptors
exec 1>&3 2>&4 3>&- 4>&-

I already checked the script with shellcheck.

The result:

In line 133:
declare -r pausearg="Press any key to continue..."
           ^-- SC2034: pausearg appears unused. Verify use (or export if used externally).

This is intentionally left for later use, for debugging:

In /opt/vmchecks/vmrun line 179:
declare -r brlan_configs_md5="/opt/vmchecks/50-ovs-brlan.md5"
           ^-- SC2034: brlan_configs_md5 appears unused. Verify use (or export if used externally).
In /opt/vmchecks/vmrun line 182:
declare -r brlan_configs_sha="/opt/vmchecks/50-ovs-brlan.sha"
           ^-- SC2034: brlan_configs_sha appears unused. Verify use (or export if used externally).

This is a false positive; it is used:

In /opt/vmchecks/vmrun line 462:
    arr_iface_virt_nonbridge=("${arr_iface_virt_nonbridge_tmp[@]}")
    ^-- SC2034: arr_iface_virt_nonbridge appears unused. Verify use (or export if used externally).

True. It's currently only initialized with values but not further used. It's kept for a possible later use.

Please review, find bugs and give hints to make them simpler and better.

\$\endgroup\$
3
\$\begingroup\$

Much of this seems ... unidiomatic for a shell script. It feels rather like a C program converted to shell.

  • You don't need to declare -f functions before hand. In fact, declare -f func_pause is an error if func_pause wasn't already a function. (Check $? after such a declare command - it should be 1.)
  • All of the declare statements that don't set a property or a value of the variable are useless.
  • You don't need to set a loop variable to empty before the loop. I'm not sure what the point in setting it to empty after the loop is, either.
  • You have saved and restored stdin and stdout, but otherwise fd's 3 and 4 are unused in the rest of the script.
  • Functions return the exit status of the last command executed in the function body. The only way shell functions don't return anything is if the shell exited in the middle of a function.
  • read is a built-in, not an external command.
  • echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t ... is repeated so often, it should be a function, which would avoid the surprisingly large number of echo -e <&2s.

  • Shellcheck complains that those variables are unused because you use indirection, but indirection is completely unnecessary here. The array arr_brlan_config_files could just as well have been:

    declare -a -r arr_brlan_config_files=( # network config files
        # for openvswitch lan bridge interface
        "/etc/systemd/network/50-ovs-brlan.network"
        # for openvswitch lan bridge interface that should be used at system startup
        "/etc/systemd/network/50-ovs-brlan.startup"
        # for openvswitch lan bridge interface to use after first virtual machine started up
        "/etc/systemd/network/50-ovs-brlan.aftervm"
    )
    

    This would eliminate the indirection later on. Or if you really wanted to name these files, use an associative array:

    declare -A -r arr_brlan_config_files=( # network config files
        # for openvswitch lan bridge interface
        ["brlan_config"]="/etc/systemd/network/50-ovs-brlan.network"
        # for openvswitch lan bridge interface that should be used at system startup
        ["brlan_config_startup"]="/etc/systemd/network/50-ovs-brlan.startup"
        # for openvswitch lan bridge interface to use after first virtual machine started up
        ["brlan_config_aftervm"]="/etc/systemd/network/50-ovs-brlan.aftervm"
    )
    
  • The instances of setting and restoring IFS seems to be for reading in an array from another array (but other functions show you know don't need to use read here) or reading from a file, for which you can use mapfile without worrying about IFS. So all instances of modifying IFS are avoidable.

  • md5sum can perform checks for you, if you use the -c option and give a file in the right format. md5sum's output is in the right format.
  • The pattern function_that_accepts_only_one_arg followed by for ... in ...; do function_that_accepts_only_one_arg arg; done is so pervasive that it might better to simply have the functions accept multiple arguments and do the looping in the function, or use a function that does the looping for you:

    loop_a_function () {
        local func="$1"
        shift
        for arg
        do
            "$func" "$arg"
        done
    }
    loop_a_function some_func "${some_array[@]}"
    

I suspect the current code is nearly double the length it needs to be, without any additionally clarity gained from the length. I strongly advise waiting for the delirium to pass and rewriting the script after.

\$\endgroup\$
  • \$\begingroup\$ Is there a way to use your suggested solution loop_a_function in 2 stacked loops like: for checksum_file in "${arr_checksum_brlan_config_files[@]}" do func_loop_function func_verify_checksums "${arr_checksum[@]}" where the inner loop needs the variable checksum_file from the outer loop too? \$\endgroup\$ – user181621 Oct 10 '18 at 20:47
0
\$\begingroup\$

I reworked the script, several functions are now completely rewritten. From my tests so far everything seems to be working as expected. Pleas review again for optimizations and potential bugs.

#!/bin/bash

#  vmrun
#  
#  Copyright 2018 emwe <>
#  
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#  
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following disclaimer
#    in the documentation and/or other materials provided with the
#    distribution.
#  * Neither the name of the  nor the names of its
#    contributors may be used to endorse or promote products derived from
#    this software without specific prior written permission.
#  
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
#  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
#  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
#  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 

########################################################################
### Purpose of this script is:                                       ###
###  - detect all network interfaces                                 ###
###  - find which of them are physical interfaces                    ###
###  - determine which of them are bridges                           ### 
###  - check if physical interfaces are up                           ###
###  - check if bridge interfaces are up                             ###
###  - determine if physical interfaces have IPv4 addresses          ###
###  - check if physical interfaces have IPv6 addresses              ###
###  - delete global IP addresses from physical interfaces           ###
###  - delete link local IP addresses from physical interfaces       ###
###  - check if wan bridge interface has an IPv4 address             ###
###  - check if wan bridge interface has global IPv6 addresses       ###
###  - delete global IPv6 addresses from wan bridge interface        ###
###  - check if wan bridge interface has link local IPv6 addresses   ###
###  - delete link local IPv6 addresses from wan bridge interface    ###
###  - check if other bridge interfaces except the lan bridge        ###
###    interface have an IPv4 address                                ###
###  - delete IPv4 addresses from those interfaces                   ###
###  - check if other bridge interfaces except the lan bridge        ###
###  - interface have IPv6 addresses                                 ###
###  - delete IPv6 addresses from those interfaces                   ###
###  - check if spezific vm vm1_name is running                      ###
###  - start specific vm vm1_name if it is not running               ###
###  - check if this specific vm vm1_name is now running             ###
###  - change network configuration for lan bridge interface to      ###
###    use dhcp                                                      ###
###  - restart systemd-networkd to reflect new network configuration ###
###    for lan bridge interface                                      ###
###  - verify that lan bridge interface got IPv4 and IPv6 addresses  ###
###  - start other vms on purpose                                    ###
###  - verify that other vms are running                             ###
###  - log everything to a log file                                  ###
########################################################################

########################################################################
###                                                                  ###
### uncomment to enable limited debugging                            ###
###                                                                  ###
### -x xtrace                                                        ###
###    Write each command (preceded by the value of the PS4 variable ###
###    subjected to parameter expansion and arithmetic expansion) to ###
###    standard error before it is executed.  Useful for debugging.  ###
###                                                                  ###
########################################################################
# set -x

########################################################################
###                                                                  ###
### uncomment to check script syntax                                 ###
###                                                                  ###
### -n noexec                                                        ###
###    If not interactive, read commands but do not execute them.    ###
###    This is useful for checking the syntax of shell scripts.      ###
###                                                                  ###
########################################################################
# set -n

########################################################################
###                                                                  ###
### uncomment to write the shell input to standard error             ###
###                                                                  ###
### -v verbose                                                       ###
###    The shell writes its input to standard error as it is read.   ###
###    Useful for debugging.                                         ###
###                                                                  ###
########################################################################
# set -v

########################################################################
###                                                                  ###
### uncomment to treat unset variables and parameters as an error    ###
### when performing parameter expansion                              ###
###                                      ###
### -u unset                                                         ###
###    Treat unset variables and parameters other than the special   ###
###    parameters ?@? or ?*? as an error when performing parameter   ###
###    expansion. An error message will be written to the standard   ###
###    error, and a non-interactive shell will exit.                 ###
###    Useful for debugging.                                         ###
###                                                                  ###
########################################################################
# set -u

########################################################################
###                                                                  ###
### uncomment to send all output to vmrun.log file                   ###
### save stdout and stderr to file descriptors 3 and 4, then         ###
### redirect them to /var/log/vmrun.log                              ###
###                                                                  ###
########################################################################
exec &> /var/log/vmrun.log

########################################################################
###                                                                  ###
### declare global variables                                         ###
###                                                                  ###
########################################################################

# equivalent for DOS pause command
declare -r pausearg="Press any key to continue..."
# naming convention, bridge interfaces should start with br
declare -r bridgeinterfacestart="br"
# lan bridge interface
declare -r lanbr="brlan"
# string variable for IPv4 address of lan bridge interface
declare -r lanbr_ipv4_addr="192.168.3.4"
# wan bridge interface
# declare -r wanbr="brwan"
# dmz bridge interface
# declare -r dmzbr="brdmz"
# amount of seconds to sleep
declare -r sleeptime=3
# max counter value for loops
declare -r maxcounter=15
# string varibale for vm state shut off when locale is not set or C
declare -r vmstate_shutoff="shut off"
# string varibale for vm state running when locale is not set or C
declare -r vmstate_running="running"
# To handle the state of the vms correctly you need to set the
# variables vmstate_localized_shutoff and vmstate_localized_running in
# the "Global variables" section to the values the command
# "virsh list --all" returns for machines in shut down and running state
# for your locale
# In this script they are set for german language
# string variable for vm state shut off when locale set to german language
declare -r vmstate_shutoff_localized="ausschalten"
# string variable for vm state running when locale set to german language
declare -r vmstate_running_localized="laufend"
# name of first vm
declare -r vm1_name="lede"
# IPv4 address of vm1 for ping
declare -r vm1_ipv4_addr="192.168.3.1"
# boolean variable vor vm status
declare vmstate=2
# string variable vor vm status
declare vmstatus=""
# associative array for network config files
declare -A -r arr_brlan_config_files=( # network config files
    # for openvswitch lan bridge interface
    ["brlan_config"]="/etc/systemd/network/50-ovs-brlan.network"
    # for openvswitch lan bridge interface that should be used at system startup
    ["brlan_config_startup"]="/etc/systemd/network/50-ovs-brlan.startup"
    # for openvswitch lan bridge interface to use after first virtual machine started up
    ["brlan_config_aftervm"]="/etc/systemd/network/50-ovs-brlan.aftervm"
)
# associative array for checksum files
#declare -r -a arr_checksum_brlan_config_files=(brlan_configs_md5 brlan_configs_sha)
declare -A -r arr_checksum_brlan_config_files=(# checksum files
    # with md5 chhecksums for network config files for openvswitch lan bridge interface
    ["brlan_configs_md5"]="/opt/vmchecks/50-ovs-brlan.md5"
    # with sha512 checksums for network config files for openvswitch lan bridge interface
    ["brlan_configs_sha"]="/opt/vmchecks/50-ovs-brlan.sha"
)
# array with needed external programs
declare -a arr_ext_programs_needed=(md5sum sha512sum ip awk sed lshw grep ethtool systemctl cp diff virsh sleep date cat sysctl cut)

########################################################################
###  name: func_echo                                                 ###
###  function to produce output with a verbose result of an          ###
###  operation                                                       ###    
###                                                                  ###
###  @param                                                          ###
###  string to output                                                ###
########################################################################
function func_echo
{
    echo -e >&2 "$(date '+%Y-%m-%d %H:%M:%S')\\t$1"
}

########################################################################
###  name: func_pause                                                ###
###  function emulate the DOS pause command                          ###    
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_pause
{
    read -n1 -r -p "$*"
}

########################################################################
###  name: func_loop_function                                        ###
###  loops a function                                                ###
###                                                                  ###
###  @param                                                          ###
###  func_loop_function = function to loop                           ###
###  one or more values for function to loop                         ###
########################################################################
function func_loop_function
{
    local func_to_loop="$1"
    local arg=""
    shift
    for arg
    do
        "$func_to_loop" "$arg"
    done
}

########################################################################
###  name: func_needed_ext_progs                                     ###
###  function to check if all needed external programs are installed ###    
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_needed_ext_progs
{
    if [ -z "$(command -v "$1")" ]
    then
        func_echo "I require $1 but could not find it. Aborting."
        exit 1
    else
        func_echo "External progamm $1 found."
    fi
}

########################################################################
###  name: func_arr_iface_all                                        ###
###  function to get an array with all known interfaces excluding    ###
###  loopback (lo) interface                                         ###     
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_all
{
    local i=0

# solution found here: https://stackoverflow.com/questions/16860877/remove-an-element-from-a-bash-array
    for ((i; i<${#arr_iface_all[@]}; i++))
    do
        if [ "${arr_iface_all[i]}" == "$1" ]
        then
            unset 'arr_iface_all[i]'
        fi
    done
}

########################################################################
###  name: func_arr_iface_all_without_lan                            ###
###  function to build an array with all known interfaces from       ###
###  arr_iface_all excluding the opnvswitch lan bridge interface     ###     
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_all_without_lan
{
    local -i i=0
# solution found here: https://stackoverflow.com/questions/16860877/remove-an-element-from-a-bash-array
    for ((i; i<${#arr_iface_all_without_lan[@]}; i++))
    do
        if [ "${arr_iface_all_without_lan[i]}" == "$1" ]
        then
            unset 'arr_iface_all_without_lan[i]'
        fi
    done
}

########################################################################
###  name: func_arr_iface_phy                                        ###
###  function to get an array with all physical interfaces           ###    
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_phy
{
# get list of physical interfaces identified by lshw -c network -businfo 
# assuming only physical interfaces have a non empty businfo field
    mapfile -t arr_iface_phy < <(lshw -c network -businfo | grep '^[^ B=]' | awk '{ print $2 }')
}

########################################################################
###  name: func_arr_iface_virt                                       ###
###  function to get an array with all virtual interfaces by deleting###
###  all physical interfaces from array of all known interfaces      ###
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
# using solution from https://stackoverflow.com/questions/10020148/bash-delete-items-present-in-one-array-from-another
function func_arr_iface_virt
{
    local -i i=0
    # solution found here: https://stackoverflow.com/questions/16860877/remove-an-element-from-a-bash-array
    for ((i; i<${#arr_iface_virt[@]}; i++))
    do
        if [ "${arr_iface_virt[i]}" == "$1" ]
        then
            unset 'arr_iface_virt[i]'
        fi
    done
}

########################################################################
###  name: func_arr_iface_virt_bridge                                ###
###  function to get an array with all virtual bridge interfaces by  ###
###  deleting all virtual non bridge interfaces from array of all    ###
###  virtual interfaces                                              ###
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_virt_bridge
{
# extract bridge interfaces from array with virtual interfaces
    if [[ "$1" == "$bridgeinterfacestart"*  ]]
    then
        arr_iface_virt_bridge+=( "$1" )
    fi
}

########################################################################
###  name: func_arr_iface_virt_nonbridge                             ###
###  function to get an array with all virtual nonbridge interfaces  ###
###  by deleting all virtual bridge interfaces from array of all     ###
###  virtual interfaces                                              ###
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_virt_nonbridge
{   
# extract nonbridge interfaces from virtual interfaces
    if [[ "$1" != "$bridgeinterfacestart"*  ]]
    then
        arr_iface_virt_nonbridge+=( "$1")
    fi
}

########################################################################
###  name: func_arr_iface_virt_ovsbridge                             ###
###  function to get an array with all virtual openvswitch bridge    ###
###  interfaces by deleting all non openvswitch virtual bridge       ###
###  interfaces from array of all virtual bridge interfaces          ###
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_virt_ovsbridge
{
    if ethtool -i "$1" | grep -q openvswitch
    then
        arr_iface_virt_ovsbridge+=( "$1" )
    fi
}

########################################################################
###  name: func_arr_iface_virt_ovsbridge_without_lan                 ###
###  function to get an array with all virtual openvswitch bridge    ###
###  interfaces except the openvsiwtch virtual lan bridge interface  ###
###  by deleting all the openvswitch virtual lan bridge interface    ###
###  from array of all virtual openvswitch bridge interfaces         ###
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_arr_iface_virt_ovsbridge_whitout_lan
{
    if [ "$1" != "$lanbr" ]
    then
        arr_iface_virt_ovsbridge_without_lan+=( "$1" )
    fi
}

########################################################################
###  name: func_iface_phy_carrier                                    ###
###  function to test if all physical interfaces are connected       ###
###                                                                  ###
###  @param                                                          ###
###  no arguments required                                           ###
########################################################################
function func_iface_phy_carrier
{
    local -i loc_maxcount=$((maxcounter-5))
    local -i i=0

    if [ "$(grep "" /sys/class/net/"$1"/carrier)" -ne 1 ]
    then
        for ((i; i<=loc_maxcount; i++))
        do
            sleep "$sleeptime"s
            if [ "$(grep "" /sys/class/net/"$1"/carrier)" -eq 1 ]
            then
                break
            else
                func_echo "interface $1 has no carrier after "$((i * sleeptime))"s waiting"
            fi
        done
        if [[ $i -gt $loc_maxcount ]]
        then
            func_echo "I require physical interface ${1} connected but it's not. Aborting."
            exit 1
        fi
    else
        func_echo "Physical interface ${1} is connected. OK."
    fi
}

########################################################################
###  name: func_iface_up                                             ###
###  function to test if an interface is up                          ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
########################################################################
function func_iface_up
{
    local -i loc_maxcount=$((maxcounter-5))
    local -i i=0

    if ! ip link show "$1" | grep -q '\bUP\b'
    then
        for ((i; i<=loc_maxcount; i++))
        do
            if ip link show "$1" | grep -q '\bUP\b'
            then
                break
            else
                func_echo "interface $1 is not up after "$((i * sleeptime))"s waiting"
            fi
        done
        if [[ $i -gt $loc_maxcount ]]
        then
            func_echo "I require physical interface ${1} up but it's not. Aborting."
            exit 1
        fi
    else 
        func_echo "Interface ${1} is UP. OK."
    fi
}

########################################################################
###  name: func_iface_ipv4                                           ###
###  function to test if an interface has an IPv4 address            ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
########################################################################
function func_iface_ipv4
{
    if [[ "$(ip -4 addr show "$1")" ]]
    then
        func_echo "Interface $1 has an IPv4 address."
        arr_iface_withip+=( "$1" )
    else
        func_echo "Interface $1 has no IPv4 address."
    fi
}

########################################################################
###  name: func_iface_del_ipv4                                       ###
###  function to delete IPv4 address from an interface               ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
########################################################################
function func_iface_del_ipv4
{
    local -a loc_arr_addr=()
    local addr

    loc_arr_addr=("$(ip -4 addr show "$1" | grep '\binet\b' | awk '{ print $2 }')")
    for addr in "${loc_arr_addr[@]}"
    do
        ip addr del "$addr" dev "$1"
    done
}

########################################################################
###  name: func_iface_del__test_ipv4                                 ###
###  function to test if IPv4 addresses were deleted from interface  ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
########################################################################
function func_iface_del_test_ipv4
{
    if [[ -z $(ip -4 addr show "$1" | grep '\binet\b' | awk '{ print $2 }') ]]
    then
        func_echo "IPv4 Addresses successfully deleted from $1."
    else
        func_echo "IPv4 Addresses not deleted from $1. Aborting."
        exit 1
    fi
}

########################################################################
###                                                                  ###
###  name: func_iface_ipv6                                           ###
###  function to test if an interface has an IPv6 address            ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_ipv6
{
    if [ "$(ip -6 addr show "$1")" ]
    then
        func_echo "Interface $1 has an IPv6 address."
        arr_iface_withip+=( "$1" )
    else
        func_echo "Interface $1 has no IPv6 address."
    fi
}

########################################################################
###                                                                  ###
###  name: func_iface_del_ipv6                                       ###
###  function to delete IPv6 addresses except the ones starting with ###
###  fe80: from an interface                                         ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_del_ipv6
{
    local -a loc_arr_addr=()
    local addr

    loc_arr_addr=("$(ip -6 addr show brlan | grep '\binet6\b' | awk '{ print $2 }' | grep -v '^fe80')")
    for addr in "${loc_arr_addr[@]}"
    do
        if [ -n "$addr" ]
        then
            func_echo "IPv6 address on interface $1 starts not with fe80:. I will delete it."
            ip -6 addr del "$addr" dev "$1"
        fi
    done
}

########################################################################
###                                                                  ###
###  name: func_iface_del_ipv6_fe80                                  ###
###  function to delete IPv6 addresses starting with fe80: from an   ###
###  interface                                                       ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_del_ipv6_fe80
{
    local -a loc_arr_addr=()
    local addr

    loc_arr_addr=("$(ip -6 addr show brlan | grep '\binet6\b' | awk '{ print $2 }' | grep '^fe80')")
    for addr in "${loc_arr_addr[@]}"
    do
        if [ -n "$addr" ]
        then
            func_echo "IPv6 address on interface $1 starts with fe80:. I will delete it."
            ip -6 addr del "$addr" dev "$1"
        fi
    done
}

########################################################################
###                                                                  ###
###  name: func_iface_del_test_ipv6                                 ###
###  function to test if all IPv6 addresses not starting with fe80:  ###
###  were deleted from interface                                     ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_del_test_ipv6
{
    local -a loc_arr_addr=()
    local addr=""
    local -i i=0

    loc_arr_addr=("$(ip -6 addr show brlan | grep '\binet6\b' | awk '{ print $2 }' | grep -v '^fe80')")
    if [ ${#loc_arr_addr[@]} -ne 0 ]
    then
        for ((i; i<${#loc_arr_addr[@]}; i++))
        do
            if [ -z "${loc_arr_addr[i]}" ]
            then
                unset 'loc_arr_addr[i]'
            fi
        done
    fi
    if [ ${#loc_arr_addr[@]} -ne 0 ]
    then
        func_echo "Not all IPv6 addresses not starting with fe80: were deleted from interface $1. Aborting."
        func_echo "Addresses not deleted are: ${loc_arr_addr[*]} länge=${#loc_arr_addr[@]}"
        exit 1
    else
        func_echo "All IPv6 addresses not starting with fe80: were deleted from interface $1. OK."
    fi
}

########################################################################
###                                                                  ###
###  name: func_iface_del__test_ipv6_fe80                            ###
###  function to test if all IPv6 addresses starting with fe80: were ###
###  deleted from interface                                          ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_del_test_ipv6_fe80
{
    local -a loc_arr_addr=()
    local addr=""
    local -i i=0

    loc_arr_addr=("$(ip -6 addr show brlan | grep '\binet6\b' | awk '{ print $2 }' | grep '^fe80')")
    if [ ${#loc_arr_addr[@]} -ne 0 ]
    then
        for ((i; i<${#loc_arr_addr[@]}; i++))
        do
            if [ -z "${loc_arr_addr[i]}" ]
            then
                unset 'loc_arr_addr[i]'
            fi
        done
    fi
    if [ ${#loc_arr_addr[@]} -ne 0 ]
    then
        func_echo "Not all IPv6 addresses starting with fe80: were deleted from interface $1. Aborting."
        func_echo "Addresses not deleted are: ${loc_arr_addr[*]} länge=${#loc_arr_addr[@]}"
        exit 1
    else
        func_echo "All IPv6 addresses starting with fe80: were deleted from interface $1. OK."
    fi
}

########################################################################
###                                                                  ###
###  name: func_iface_ipv6_disable                                   ###
###  function to disable IPv6 on an interface                        ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_ipv6_disable
{
    sysctl -w net.ipv6.conf."$1".disable_ipv6=1
}

########################################################################
###                                                                  ###
###  name: func_iface_ipv6_disabled_test                             ###
###  function to test if IPv6 is disabled on an interface            ###
###                                                                  ###
###  @param                                                          ###
###  interface name required                                         ###
###                                                                  ###
########################################################################
function func_iface_ipv6_disabled_test
{
    if [ "$( cat /proc/sys/net/ipv6/conf/"$1"/disable_ipv6 )" -eq 1 ]
    then
        func_echo "IPv6 is disabled on $1."
    else
        func_echo "IPv6 is not disabled on $1. Aborting"
        exit 1
    fi
}

########################################################################
###                                                                  ###
###  name: func_vm_state                                             ###
###  function to get status of a virtual machine                     ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###                                                                  ###
########################################################################
function func_vm_state
{
    local -i i=1

    for ((i; i<=maxcounter; i++))
    do
        vmstatus=$( virsh list --all | grep "$1" | awk '{print $3}' )
        case "$vmstatus" in
            "$vmstate_shutoff"|"$vmstate_shutoff_localized")
                vmstate=0
                break
                ;;
            "$vmstate_running"|"$vmstate_running_localized")
                vmstate=1
                break
                ;;
            *)
                vmstate=2
                ;;
        esac
        sleep "$sleeptime"s
    done
    if [ $vmstate -eq 2 ]
    then
        func_echo "Could not get status of vm $1 after "$((maxcounter * sleeptime))"s waiting."
    fi
}

########################################################################
###                                                                  ###
###  name: func_vm_start                                             ###
###  function to get status of a virtual machine                     ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###                                                                  ###
########################################################################
function func_vm_start
{
    local loc_vmstatus
    local -i i=0

    virsh start "$1" &>/dev/null
    for ((i; i<=maxcounter; i++))
    do
        sleep "$sleeptime"s
        loc_vmstatus=$( virsh list --all | grep "$1" | awk '{print $3}' )
        if [ "$loc_vmstatus" == "$vmstate_running" ] || [ "$loc_vmstatus" == "$vmstate_running_localized" ]
        then
            break
        fi
    done
}

########################################################################
###                                                                  ###
###  name: func_vm_start_verify                                      ###
###  function to get status of a virtual machine                     ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###                                                                  ###
########################################################################
function func_vm_start_verify
{
    if [ $vmstate -eq 1 ]
    then
        func_echo "Virtual machine $1 is running."
    else
        func_echo "Virtual machine $1 is not properly running"
    fi
}

########################################################################
###                                                                  ###
###  name: func_vm_start_completed                                   ###
###  function to wait for a virtual machine to fully start up        ###
###  assuming it is when it can be pinged                            ###
###                                                                  ###
###  @param                                                          ###
###  vm name required                                                ###
###  vm IPv4 address required                                        ###
###                                                                  ###
########################################################################
function func_vm_start_completed
{
    local loc_ping_success=0
    local -i maxcount=maxcounter+5
    local -i i=0

    for ((i; i<=maxcount; i++))
    do
        if ping -4 -w1 -c1 "$2" &>/dev/null
        then
            loc_ping_success=1
            func_echo "Start up of virtual machine $1 completed."
            break
        else
            loc_ping_success=0
            sleep "$sleeptime"s
        fi
    done
    if [ $loc_ping_success -eq 0 ]
    then
        func_echo "Start up of virtual machine $1 did not complete after "$((maxcount * sleeptime))"s. Aborting."
        exit 1
    fi
}

########################################################################
###                                                                  ###
###  name: func_file_exists                                          ###
###  function to check if file exists                                ###    
###                                                                  ###
###  @param                                                          ###
###  filename with absolute path                                     ###
###                                                                  ###
########################################################################
function func_file_exists
{
    if ! [ -f "$1" ]
    then
        func_echo "$1 file does not exist. Aborting."
        exit 1
    else
        func_echo "$1 file exists."
    fi
}

########################################################################
###                                                                  ###
###  name: func_verify_checksums                                     ###
###  function verify the checksums of the network coonfig files      ###
###  against the ones stored in the checksum files                   ###
###                                                                  ###
###  @param                                                          ###
###  filename with absolute path                                     ###
###                                                                  ###
########################################################################
function func_verify_checksums
{
    checksum_filename_from_arr_checksum="$(echo "$1" | awk '{print $2}')"
        case "${checksum_file:(-4)}" in
            ".md5")
                if [ "$(md5sum "$checksum_filename_from_arr_checksum" | awk '{print $1}')" == "$(echo "$1" | awk '{print $1}')" ]
                then
                    func_echo "$checksum_filename_from_arr_checksum matches md5 checksum stored in ${checksum_file}."
                else
                    func_echo "$checksum_filename_from_arr_checksum does not match md5 checksum stored in ${checksum_file}. Aborting."
                    exit 1
                fi
                ;;
            ".sha")
                if [ "$(sha512sum "$checksum_filename_from_arr_checksum" | awk '{print $1}')" == "$(echo "$1" | awk '{print $1}')" ]
                then
                    func_echo "$checksum_filename_from_arr_checksum matches sha512 checksum stored in ${checksum_file}."
                else
                    func_echo "$checksum_filename_from_arr_checksum does not match sha512 checksum stored in ${checksum_file}. Aborting."
                    exit 1
                fi
                ;;
            *)
                func_echo "No matching checksum file found. Aborting."
                exit 1
                ;;
        esac
}

########################################################################
### main program                                                     ###
### requires no arguments                                            ###
########################################################################
# check if all needed external programs are installed
func_echo "Test if all needed external programms are installed."
func_loop_function func_needed_ext_progs "${arr_ext_programs_needed[@]}"
func_echo "Test if all needed external programms are installed finished."
# get list of existing interfaces in array variable arr_iface_all
func_echo "Get list of all known network interfaces except the loopback interface."
mapfile -t arr_iface_all < <( ip -o link | awk '{ print $2 }' | cut -f1 -d":" )
func_loop_function func_arr_iface_all "lo"
func_echo "Get list of all known network interfaces except loopback interface finished."
# build list of all interfaces openvswitch lan bridge interface from
#list of all interfaces except loopback
func_echo "Build list of all known network interfaces except the openvswitch lan bridge interface."
arr_iface_all_without_lan=( "${arr_iface_all[@]}" )
func_loop_function func_arr_iface_all_without_lan "$lanbr"
func_echo "Build list of all known network interfaces except the openvswitch lan bridge interface finished."
# get list of physical interfaces in array variable arr_iface_phy
func_echo "Get list of all physical networkinterfaces."
func_arr_iface_phy
func_echo "Get list of all physical networkinterfaces finished."
# build list of virtual interfaces
func_echo "Start building array with virtual interfaces."
arr_iface_virt=( "${arr_iface_all[@]}" )
func_loop_function func_arr_iface_virt "${arr_iface_phy[@]}"
func_echo "Start building array with virtual interfaces finished."
# build list of virtual bridge interfaces
func_echo "Start building array with virtual bridge interfaces."
func_loop_function  func_arr_iface_virt_bridge "${arr_iface_virt[@]}"
func_echo "Start building array with virtual bridge interfaces finished"
# build list of virtual non bridge interfaces
func_echo "Start building array with virtual non bridge interfaces."
func_loop_function func_arr_iface_virt_nonbridge "${arr_iface_virt[@]}"
func_echo "Start building array with virtual non bridge interfaces finished"
# build list of virtual openvswitch bridge interfaces
func_echo "Start building array with virtual openvswitch bridge interfaces."
func_loop_function func_arr_iface_virt_ovsbridge "${arr_iface_virt_bridge[@]}"
func_echo "Start building array with virtual openvswitch bridge interfaces finished."
# build an array without the openvswitch lan bridge interface from the
# array with the openvswitch bridge interfaces
func_echo "Start building array of virtual openvswitch bridge interfaces without virtual lan openvswitch bridge interface."
func_loop_function func_arr_iface_virt_ovsbridge_whitout_lan "${arr_iface_virt_ovsbridge[@]}"
func_echo "Start building array of virtual openvswitch bridge interfaces without virtual lan openvswitch bridge interface finished."
# check if all physical interfaces have a carrier, required
func_echo "Start test if physical interfaces have a carrier."
func_loop_function func_iface_phy_carrier "${arr_iface_phy[@]}"
func_echo "Test if physical interfaces have a carrier finished."
# check if all physical interfaces are up, required
func_echo "Start test if physical interfaces are up."
func_loop_function func_iface_up "${arr_iface_phy[@]}"
func_echo "Test if physical interfaces are up finished."
# check if all openvswitch bridge interfaces are up, required
func_echo "Start test if virtual openvswitch bridge interfaces are up."
func_loop_function func_iface_up "${arr_iface_virt_ovsbridge[@]}"
func_echo "Test if virtual openvswitch bridge interfaces are up finished."

# in this system all interfaces except loopback and openvswitch lan
# bridge interface must have no IPv4 address
func_echo "Start test if interfaces except loopback and openvswitch lan bridge interface have an IPv4 address."
arr_iface_withip=()
func_loop_function func_iface_ipv4 "${arr_iface_all_without_lan[@]}"
func_echo "Start test if interfaces except loopback and openvswitch lan bridge interface have an IPv4 address finished."
# deleting IPv4 addresses from interfaces except loopback and
# openvswitch lan interface
func_echo "Start deleting IPv4 addresses from interfaces except loopback and openvswitch lan bridge interface."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_echo "Some interfaces except loopback and openvswitch lan bridge interface have an IPv4 address, deleting it"
    func_loop_function func_iface_del_ipv4 "${arr_iface_withip[@]}"
else
    func_echo "No interfaces except loopback and openvswitch lan bridge interface have an IPv4 address. Nothing to do."
fi
func_echo "Deleting IPv4 addresses from interfaces except loopback and openvswitch lan bridge interface finished"
# test if IPv4 adresses from interfaces except loopback and openvswitch
# lan interface are deleted
func_echo "Test if IPv4 addresses from interfaces except loopback and openvswitch lan bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_loop_function func_iface_del_test_ipv4 "${arr_iface_withip[@]}"
else
    func_echo "No interfaces except loopback and openvswitch lan bridge interface have an IPv4 address. Nothing to do."
fi
func_echo "Test if IPv4 addresses from interfaces except loopback and openvswitch lan bridge interface are deleted finished."
unset arr_iface_withip

# in this system all interfaces except loopback and openvswitch lan
# bridge interface must have no IPv6 address
func_echo "Start test if interfaces except loopback and openvswitch lan bridge interface have an IPv6 address."
arr_iface_withip=()
func_loop_function func_iface_ipv6 "${arr_iface_all_without_lan[@]}"
func_echo "Test if interfaces except loopback and openvswitch lan bridge interface have an IPv6 address finished."
# delete IPv6 addresses from interfaces except loopback and openvswitch
# lan bridge interface except for the ones starting with "fe80:"
func_echo "Start deleting IPv6 addresses not starting with fe80: from interfaces except loopback and openvswitch lan bridge interface."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_echo "Some interfaces except loopback and openvswitch lan bridge interface have IPv6 addresses, deleting them if they start not with fe80:."
    func_loop_function func_iface_del_ipv6 "${arr_iface_withip[@]}"
else
    func_echo "No interfaces except loopback and openvswitch lan bridge interface have IPv6 addresses. Nothing to do."
fi
func_echo "Deleting IPv6 addresses not starting with fe80: from interfaces except loopback and openvswitch lan bridge interface finished."
# test if IPv6 adresses except the ones starting with fe80: are deleted
# from interfaces except loopback and openvswitch lan bridge interface
func_echo "Test if IPv6 addresses not starting with fe80: from interfaces except loopback and openvswitch lan bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_loop_function func_iface_del_test_ipv6 "${arr_iface_withip[@]}"
else
    func_echo "No interfaces except loopback and openvswitch lan bridge interface have IPv6 addresses. Nothing to do."
fi
func_echo "Test if IPv6 addresses from interfaces except loopback and openvswitch lan bridge interface not starting with fe80: are deleted finished."
# delete IPv6 addresses from interfaces except loopback and openvswitch
# lan bridge interface starting with "fe80:"
func_echo "Start deleting IPv6 addresses starting with fe80: from interfaces except loopback and openvswitch lan bridge interface."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_echo "Some interfaces except loopback and openvswitch lan bridge interface have IPv6 addresses, deleting them if they start with fe80:."
    func_loop_function func_iface_del_ipv6_fe80 "${arr_iface_withip[@]}"
else
    func_echo "No interfaces except loopback and openvswitch lan bridge interface have IPv6 addresses. Nothing to do."
fi
func_echo "Deleting IPv6 addresses starting with fe80: from interfaces except loopback and openvswitch lan bridge interface finished."
# test if IPv6 adresses starting with fe80: from interfaces except
# loopback and openvswitch lan bridge interfaceare deleted
func_echo "Test if IPv6 addresses from physical interfaces starting with fe80: are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_loop_function func_iface_del_test_ipv6_fe80 "${arr_iface_withip[@]}"
else
    func_echo "No interfaces except loopback and openvswitch lan bridge interface have IPv6 addresses. Nothing to do."
fi
func_echo "Test if IPv6 addresses from interfaces except loopback and openvswitch lan bridge interface starting with fe80: are deleted finished."

# disabling IPv6 on all interfaces except loopback and openvswitch lan
# bridge interface to make sure that no communication via IPv6 is possible
#func_echo "Start disabling IPv6 on interfaces except loopback and openvswitch lan bridge interface"
#func_loop_function func_iface_ipv6_disable "${arr_iface_all_without_lan[@]}"
#func_echo "Disabling IPv6 on interfaces except loopback and openvswitch lan bridge interface finished."
# test if IPv6 on interfaces except loopback and openvswitch lan bridge
# interface is disabled
#func_echo "Test if IPv6 on all interfaces except loopback and openvswitch lan bridge interface is disabled"
#func_loop_function func_iface_ipv6_disabled_test "${arr_iface_all_without_lan[@]}"
#func_echo "Test if IPv6 on interfaces except loopback and openvswitch lan bridge interface is disabled finished."

# test if virtual machine vm1_name is running and start it if not
# get status of virtual machine vm1_name
func_echo "Get status of virtual machine $vm1_name."
func_vm_state "$vm1_name"
func_echo "Getting status of virtual machine $vm1_name finished. State is verbose: $vmstatus and for internal use: $vmstate."
unset vmstatus
# starting virtual machine vm1_name if not running, do nothing if already running
# aborting script if not in running or shut down state
func_echo "Starting virtual machine $vm1_name if not running and in a state I can handle."
case $vmstate in
    0)
        func_echo "Virtual machine $vm1_name is not running, starting it."
        func_vm_start "$vm1_name"
        func_echo "Virtual machine $vm1_name started."
        ;;
    1)
        func_echo "Virtual machin $vm1_name is already running."
        ;;
    2)
        func_echo "Virtual machine vm1_name is in a status I cannot handle. Aborting."
        exit 1
        ;;
    *)
        func_echo "Something in the function to get the state of the virtual machine $1 went wrong. Aborting."
        exit 1
        ;;
esac
unset vmstate
func_echo "Starting of virtual machine $vm1_name finished."
#verifying that virtual machine vm1_name is running
func_echo "Verifying that virtual machine $vm1_name is running."
func_vm_state "$vm1_name"
func_vm_start_verify "$vm1_name"
if [ $vmstate -ne 1 ]
then
    func_echo "Virtual machine $vm1_name is not running. Aborting."
    exit 1
fi  
func_echo "Verifying that virtual machine $vm1_name is running finished."
# wait for virtual machine vm1_name to fully startup
if [ $vmstate -eq 1 ]
then
    func_echo "Wait for virtual machine $vm1_name to fully start up."
    func_vm_start_completed "$vm1_name" "$vm1_ipv4_addr"
fi
func_echo "Wait for virtual machine $vm1_name to fully start up finished."
# now the the virtual machine vm1_name is running copy new network
# config files in place, delete all IPv4 and IPv6 addresses from
# openvswitch lan bridge interface and get new ones via dhcp from
# virtual machine vm1_name
# replacing current network config file with the one for use after vm vm1_name is running
# check if all needed files exist
# check if needed network config files exist 
func_echo "Check if network config files exist."
func_loop_function func_file_exists "${arr_brlan_config_files[@]}"
func_echo "Check if network config files exist finished."
# check if needed checksum files exist
func_echo "Check if checksum files for network config files exist."
func_loop_function func_file_exists "${arr_checksum_brlan_config_files[@]}"
func_echo "Check if checksum files for network config files exist finished."
#check integrity of files against the checksum files
func_echo "Check integrity of network config files against the checksum files."
for checksum_file in "${arr_checksum_brlan_config_files[@]}"
do
    mapfile -t arr_checksum < "${checksum_file}"
    func_loop_function func_verify_checksums "${arr_checksum[@]}"
done
func_echo "Check integrity of network config files against the checksum files finished."
# copy network config file for openvswitch lan bridge interface for run
# after virtual machine vm1_name startup but only if it differs from
# current network config file and startup network config file and
# current network config file equals startup network config file
func_echo "copying startup network config file."
if ! diff -q "${arr_brlan_config_files[brlan_config]}" "${arr_brlan_config_files[brlan_config_aftervm]}" >/dev/null
then
    func_echo "${arr_brlan_config_files[brlan_config]} and ${arr_brlan_config_files[brlan_config_aftervm]} are different."
    if ! diff -q "${arr_brlan_config_files[brlan_config_aftervm]}" "${arr_brlan_config_files[brlan_config_startup]}" >/dev/null
    then
        func_echo "${arr_brlan_config_files[brlan_config_aftervm]} and ${arr_brlan_config_files[brlan_config_startup]} are different."
        if diff  -q "${arr_brlan_config_files[brlan_config]}" "${arr_brlan_config_files[brlan_config_startup]}" >/dev/null
        then
            func_echo "${arr_brlan_config_files[brlan_config]} and ${arr_brlan_config_files[brlan_config_startup]} are identical. Copying aftervm network config"
            cp -f "${arr_brlan_config_files[brlan_config_aftervm]}" "${arr_brlan_config_files[brlan_config]}"
        else
            func_echo "Network config file for use at system start differ from current network config file. You are in trouble. Aborting."
            exit 1
        fi
    else
        func_echo "Network config file for use after starting virtual machine does not differ from startup network config file. You are in trouble. Aborting."
        exit 1
    fi
else
    func_echo "Network config file for use after virtual machine start does not differ from current network config file. You are in trouble. Aborting."
    exit 1
fi
# verifying that network config file was successful copied
if diff -q "${arr_brlan_config_files[brlan_config]}" "${arr_brlan_config_files[brlan_config_aftervm]}" >/dev/null
then
    func_echo "Network config file was successful copied."
else
    func_echo "Network config file was not successful copied. Aborting."
    exit 1
fi
# check if openvswitch lan bridge interface has an IPv4 address
func_echo "Start test if openvswitch lan bridge has an IPv4 address."
arr_iface_withip=()
func_iface_ipv4 "$lanbr"
func_echo "Test if openvswitch lan bridge has an IPv4 address finished."
# deleting IPv4 addresses from openvswitch lan bridge interface
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_echo "Openvswitch lan bridge interface has an IPv4 address, deleting it"
    func_loop_function func_iface_del_ipv4 "${arr_iface_withip[@]}"
fi
func_echo "Deleting IPv4 addresses from openvswitch lan bridge interface finished."
# test if IPv4 adresses are deleted
func_echo "Start test if IPv4 addresses from openvswitch lan bridge are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_loop_function func_iface_del_test_ipv4 "${arr_iface_withip[@]}"
fi
func_echo "Test if IPv4 addresses from openvswitch lan bridge are deleted finished."
# check if the openvswitch lan bridge interface have an IPv6 address 
# except for the ones starting with "fe80:"
func_echo "Start test if the openvswitch lan bridge interface has an IPv6 address."
arr_iface_withip=()
func_iface_ipv6 "$lanbr"
func_echo "Test if openvswitch lan bridge has IPv6 addresses finished."
# delete IPv6 addresses from the openvswitch lan bridge interface except
# except for the ones starting with "fe80:"
func_echo "Start deleting IPv6 addresses from openvswitch lan bridge interface."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_echo "The openvswitch lan bridge interface has IPv6 addresses, deleting them if they start not with fe80:."
    func_loop_function func_iface_del_ipv6 "${arr_iface_withip[@]}"
fi
func_echo "Deleting IPv6 addresses from openvswitch lan bridge interface finished."
# test if IPv6 adresses not starting with fe80: are deleted
func_echo "Test if IPv6 addresses from openvswitch lan bridge interface are deleted."
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    func_loop_function func_iface_del_test_ipv6 "${arr_iface_withip[@]}"
fi
func_echo "Test if IPv6 addresses from openvswitch lan bridge interface are deleted finished."
unset arr_iface_withip

# Restarting systemd-networkd with new config file
func_echo "Restarting systemd-networkd."
systemctl restart systemd-networkd
func_echo "Restarting systemd-networkd finished."

# check if openvswitch lan bridge interface has an IPv4 address
func_echo "Start test if openvswitch lan bridge has an IPv4 address."
arr_iface_withip=()
if [ ${#arr_iface_withip[@]} -eq 0 ]
then
    for ((i=1; i<=maxcounter; i++))
    do
        func_iface_ipv4 "$lanbr"
        if [ ${#arr_iface_withip[@]} -eq 0 ]
        then
            func_echo "Interface $lanbr has no IPv4 Address sleeping ""$sleeptime""s"
            sleep "$sleeptime"s
        else
            break
        fi
    done
fi
if [ "$i" -gt "$maxcounter" ]
then
    func_echo "Openvswitch lan bridge interface did not get an IPv4 address after"$((maxcounter * sleeptime))"s waiting."
fi
unset i
if [ ${#arr_iface_withip[@]} -eq 0 ]
then
    func_echo "Openvswitch lan bridge interface does not have an IPv4 address assinging one for emergency"
    ip addr add $lanbr_ipv4_addr/24 dev $lanbr
# check if openvswitch lan bridge interface now has an IPv4 address
    if [[ $(ip -4 addr show $lanbr | grep inet | awk '{print $2}' | cut -f1 -d"/") == "$lanbr_ipv4_addr" ]]
    then
        func_echo "Openvswitch lan bridge interface now has an emergency IPv4 address. Aborting."
        exit 1
    else
        func_echo "Openvswitch lan bridge interface did not accept the emergency IPv4 address. You are in serious trouble. Aborting."
        exit 1
    fi
fi
func_echo "Test if openvswitch lan bridge has an IPv4 address finished."
# check if openvswitch lan bridge interface equals $lanbr_ipv4_addr
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    if [[ $(ip -4 addr show $lanbr | grep inet | awk '{print $2}' | cut -f1 -d"/") == "$lanbr_ipv4_addr" ]]
    then
        func_echo "Assigned IPv4 address for openvswitch lan bridge interface is correct"
    else
        func_echo "Assigned IPv4 address for openvswitch lan bridge interface is not correct. Aborting."
        exit 1
    fi
fi
# check if openvswitch lan bridge interface IPv4 address was assigned via DHCP
if [ ${#arr_iface_withip[@]} -ne 0 ]
then
    if [[ $(ip -4 addr show $lanbr | grep inet | awk '{print $7}') == "dynamic" ]]
    then
        func_echo "IPv4 address of openvswitch lan bridge interface was assigend via DHCP"
    else
        func_echo "IPv4 address of openvswitch lan bridge interface was not assigend via DHCP"
    fi
fi
arr_iface_withip=()
# final message
func_echo "Script finished"

#func_pause "$pausearg"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy