#!/usr/bin/env bash

# -------------------------------------------------------------------------- #
# Copyright 2002-2020, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
#--------------------------------------------------------------------------- #

COMMAND=${1}

# Gets IP address from a given MAC
mac2ip() {
    mac=$1

    let ip_a=0x`echo $mac | cut -d: -f 3`
    let ip_b=0x`echo $mac | cut -d: -f 4`
    let ip_c=0x`echo $mac | cut -d: -f 5`
    let ip_d=0x`echo $mac | cut -d: -f 6`

    ip="$ip_a.$ip_b.$ip_c.$ip_d"

    echo $ip
}

# Gets the network part of an IP
get_network() {
    network=$(get_iface_var "NETWORK")

    if [ -z "$network" ]; then
        IFS=. read -r i1 i2 i3 i4 <<< "$IP"
        IFS=. read -r m1 m2 m3 m4 <<< "$(get_mask)"
        network=$(printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))")
    fi

    echo $network
}

# Gets the network mask
get_mask() {
    mask=$(get_iface_var "MASK")

    if [ -z "$mask" ]; then
        mask="255.255.255.0"
    fi

    echo $mask
}

# Gets device MTU
get_mtu() {
    mtu=$(get_iface_var "MTU")

    echo $mtu
}

is_gateway() {
    if [ -z "$GATEWAY_IFACE_NUM" ]; then
        true
    else
        [ "$IFACE_NUM" = "$GATEWAY_IFACE_NUM" ]
    fi
}

# Gets the network gateway
get_gateway() {
    if is_gateway; then
        gateway=$(get_iface_var "GATEWAY")

        echo $gateway
    fi
}

# Gets the network gateway6
get_gateway6() {
    if is_gateway; then
        get_iface_var "GATEWAY6"
    fi
}

get_ip() {
    ip=$(get_iface_var "IP")

    echo $ip
}

get_iface_var() {
    var_name="${UPCASE_DEV}_$1"
    var=$(eval "echo \"\${$var_name}\"")

    echo $var
}

gen_iface_conf() {
    cat <<EOT
NETMASK=$MASK
IPADDR=$IP
EOT

    if [ -n "$GATEWAY" ]; then
        if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
            echo "default $GATEWAY - $DEV ${METRIC:+metric ${METRIC}}" \
                >> "${CONFIG_PATH}/ifroute-${DEV}"
        else
            echo "default via $GATEWAY dev $DEV ${METRIC:+metric ${METRIC}}" \
                >> "${CONFIG_PATH}/route-${DEV}"
        fi
    fi

    if [ -n "$MTU" ]; then
        echo "MTU=$MTU"
    fi
}

gen_alias_conf() {
    cat <<EOT
IPADDR${ALIAS_NUM}="${IP}"
NETMASK${ALIAS_NUM}="${MASK}"
EOT
}

gen_alias6_conf() {
    if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
        echo "IPADDR_A6A${ALIAS_NUM}=$IP6/${IP6_PREFIX_LENGTH:-64}"
    else
        IPV6ADDR_SECONDARIES="${IPV6ADDR_SECONDARIES} ${IP6}/${IP6_PREFIX_LENGTH:-64}"
    fi

    if [ -n "$IP6_ULA" ]; then
        if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
            echo "IPADDR_A6B${ALIAS_NUM}=$IP6_ULA/64"
        else
            IPV6ADDR_SECONDARIES="${IPV6ADDR_SECONDARIES} ${IP6_ULA}/64"
        fi
    fi
}

gen_iface6_conf() {
    if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
        echo "IPADDR_6A=$IP6/${IP6_PREFIX_LENGTH:-64}"

        cat <<EOT >> /etc/sysconfig/network/ifsysctl-$DEV
net.ipv6.conf.\$SYSCTL_IF.autoconf = 0
net.ipv6.conf.\$SYSCTL_IF.accept_ra = 0
EOT
    else
        cat <<EOT
IPV6INIT=yes
IPV6ADDR=$IP6/${IP6_PREFIX_LENGTH:-64}
IPV6_AUTOCONF=no
EOT
    fi

    if [ -n "$IP6_ULA" ]; then
        if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
            echo "IPADDR_6B=$IP6_ULA/64"
        else
            IPV6ADDR_SECONDARIES="${IPV6ADDR_SECONDARIES} ${IP6_ULA}/64"
        fi
    fi

    if [ -n "$GATEWAY6" ]; then
        if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
            echo "default $GATEWAY6 - $DEV" >> /etc/sysconfig/network/ifroute-$DEV
        else
            echo "IPV6_DEFAULTGW=$GATEWAY6"
        fi
    fi

    if [ -n "$MTU" ]; then
        echo "IPV6_MTU=$MTU"
    fi
}

get_interface_mac()
{
    ip link show | awk '/^[0-9]+: [A-Za-z0-9@]+:/ { device=$2; gsub(/:/, "",device); split(device,dev,"@")} /link\/ether/ { print dev[1]  " " $2 }'
}

get_context_interfaces()
{
    env | grep -E "^ETH[0-9]+_MAC=" | sed 's/_.*$//' | sort
}

get_interface_alias()
{
    env | grep -E "^ETH${INDEX}_ALIAS[0-9]+_MAC=" | cut -d '_' -f 2 | sort
}

get_dev()
{
    list="$1"
    mac="$2"

    echo "$list" | grep "$mac" | cut -d' ' -f1 | tail -n1
}

gen_network_configuration()
{
    if [ -d /etc/sysconfig/network-scripts ]; then
        CONFIG_PATH=/etc/sysconfig/network-scripts
    elif [ -d /etc/sysconfig/network ]; then
        CONFIG_PATH=/etc/sysconfig/network
    fi

    INTERFACE_MAC=$(get_interface_mac)
    CONTEXT_INTERFACES=$(get_context_interfaces)
    GATEWAY_IFACE_NUM=$(echo "$GATEWAY_IFACE" | sed 's/^ETH//')

    for interface in $CONTEXT_INTERFACES; do
        UPCASE_DEV=$interface
        MAC=$(get_iface_var "MAC")
        DEV=$(get_dev "$INTERFACE_MAC" "$MAC")
        IFACE_NUM=$(echo "$UPCASE_DEV" | sed 's/^ETH//')

        IP=$(get_ip)
        NETWORK=$(get_network)
        MASK=$(get_mask)
        MTU=$(get_mtu)
        GATEWAY=$(get_gateway)
        METRIC=$(get_iface_var "METRIC")

        IP6=$(get_iface_var "IP6")
        [[ -z $IP6 ]] && IP6=$(get_iface_var "IPV6")
        IP6_PREFIX_LENGTH=$(get_iface_var "IP6_PREFIX_LENGTH")
        IP6_ULA=$(get_iface_var "IP6_ULA")
        GATEWAY6=$(get_gateway6)

        # cumulative variable
        IPV6ADDR_SECONDARIES=''

        [ -z "${IP}${IP6}" ] && continue
        [ -z "${DEV}" ] && continue

        (
            rm -f /etc/sysconfig/network-scripts/route-$DEV
            rm -f /etc/sysconfig/network/ifroute-$DEV
            rm -f /etc/sysconfig/network/ifsysctl-$DEV

            cat <<EOT
DEVICE=$DEV
BOOTPROTO=static
NM_CONTROLLED=no
TYPE=Ethernet
EOT
            if [ "$CONFIG_PATH" = "/etc/sysconfig/network" ]; then
                echo "STARTMODE=auto"
            else
                echo "ONBOOT=yes"
            fi

            [[ -n $IP ]] && gen_iface_conf
            [[ -n $IP6 ]] && gen_iface6_conf

            INDEX=${interface: -1}
            ALIAS=$(get_interface_alias)
            ALIAS_NUM=0

            for nic_alias in $ALIAS; do
                UPCASE_DEV="ETH${INDEX}_${nic_alias}"
                IP=$(get_ip)
                MASK=$(get_mask)

                IP6=$(get_iface_var "IP6")
                [[ -z $IP6 ]] && IP6=$(get_iface_var "IPV6")
                IP6_PREFIX_LENGTH=$(get_iface_var "IP6_PREFIX_LENGTH")
                IP6_ULA=$(get_iface_var "IP6_ULA")

                EXTERNAL=$(get_iface_var "EXTERNAL")
                EXTERNAL=${EXTERNAL^^}
                DETACH=$(get_iface_var "DETACH")

                if [ -z "${DETACH}" ]; then
                    if [ -z "${EXTERNAL}" ] || [ "$EXTERNAL" = "NO" ]; then
                        [ -n "${IP}"  ] && gen_alias_conf
                        [ -n "${IP6}" ] && gen_alias6_conf

                        if [ -n "${IP}${IP6}" ]; then
                            ALIAS_NUM=$((ALIAS_NUM + 1))
                        fi
                    fi
                fi
            done

            # on Red Hats, we need just a single configuration
            # entry with all additional IPv6 addresses
            if [ -n "${IPV6ADDR_SECONDARIES}" ]; then
                echo "IPV6ADDR_SECONDARIES='${IPV6ADDR_SECONDARIES## }'"
            fi
        ) > ${CONFIG_PATH}/ifcfg-${DEV}

        ifup ${DEV}

    done
}

configure_network()
{
    gen_network_configuration

    if [ "${COMMAND}" = 'reconfigure' ]; then
        service network restart
    fi

    sleep 2
}

[ -z "$(env | cut -d= -f1 | grep -E '^ETH[0-9]+_IPV*6*')" ] && exit 0

configure_network

