#!/bin/bash

# Copyright (c) 2017 SUSE Linux GmbH
#
# This file is part of azure-bond-autoconf.
#
# azure-bond-autoconf is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# azure-bond-autoconf is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License
# along with azure-bond-autoconf.  If not, see <http://www.gnu.org/licenses/

# This script is intended to run via udev when a Hyper-V pass-through
# interface is registered ('Accelerated Networking' in Azure speak).
# The script will try to find the corresponding standard interface,
# and set up a bonding interface using the pass-through interface as
# active and the standard interface as backup slave.

SYSDIR=/sys/class/net
SYSCONFDIR=/etc/sysconfig/network
NETVSC_CLS={f8615163-df3e-46c5-913f-f2d2f965ed0e}
LOGNAME=${0##*/}

if_vf="$1"

if [ -z "$if_vf" ]; then
	logger -s -t $LOGNAME -p info "No interface name given."
	exit 1
fi

shopt -s nullglob

# -------------------------------------------------------------------
# looks up the eth interface for the given mac address
# 
get_eth_interface_by_address()
{
	local addr="$1"
	test -z "$addr" && return
	for iface_dir in ${SYSDIR}/eth* ; do
		if [ "$addr" == "$(cat ${iface_dir}/address)" ]; then
			echo ${iface_dir##*/}
			return
		fi
	done
}

# -------------------------------------------------------------------
# Write a bonding master DHCP configuration for given interfaces
#
write_bond_master_config()
{
	local if_master="$1" if_slave1="$2" if_slave2="$3"
	test -z "$if_master" -o -z "$if_slave1" -o -z "$if_slave1" && return
        cat > $SYSCONFDIR/ifcfg-$if_master <<EOF
STARTMODE="auto"
BOOTPROTO="dhcp"
BONDING_MASTER="yes"
BONDING_SLAVE_0="$if_slave1"
BONDING_SLAVE_1="$if_slave2"
BONDING_MODULE_OPTS='mode=active-backup miimon=100 primary=$if_slave1'
DHCLIENT_SET_DEFAULT_ROUTE="yes"
DHCLIENT_ROUTE_PRIORITY="10${if_master##*[!0-9]}00"
CLOUD_NETCONFIG_MANAGE="yes"
AZURE_BOND_AUTOCONF="yes"
POST_DOWN_SCRIPT="compat:suse:cloud-netconfig-cleanup"
EOF
	# NOTE: DHCLIENT_ROUTE_PRIORITY calculation only works nicely up to
	# index 9, but this should be more than any Azure instance supports.
}

# -------------------------------------------------------------------
# Write a slave configuration for given interface
#
write_bond_slave_config()
{
	local iface="$1"
	test -z "$iface" && return
	cat > $SYSCONFDIR/ifcfg-$iface <<EOF
STARTMODE="hotplug"
BOOTPROTO="none"
AZURE_BOND_AUTOCONF="yes"
EOF
}

addr=$(cat $SYSDIR/$if_vf/address)
if [ -z "$addr" ]; then
	logger -s -t $LOGNAME -p warn "Could not read address of $IF_FACE"
	exit 1
fi

if_eth=$(get_eth_interface_by_address $addr)
if [ -z "$if_eth" ]; then
	logger -s -t $LOGNAME -p warn "Could not find eth pair interface for $IF_FACE"
	exit 1
fi

# Derive bond interface index from eth interface, since that will prevent index
# clashes of bonding masters and regular eth interfaces, and cloud-netconfig
# uses the index for route table names. Also vf interface name may not actually
# end in a digit.
if_bond="bond${if_eth##*[!0-9]}"

# in case the interface is up, take it down before rewriting the config
if systemctl is-active wickedd.service ; then
	/usr/sbin/wicked ifdown $if_eth 2>&1 | logger -s -t $LOGNAME -p info
fi

# Write configuration files
if [ ! -f "${SYSCONFDIR}/ifcfg-$if_bond" ]; then
  logger -s -t $LOGNAME -p info "Creating bonding master config for $if_bond"
  write_bond_master_config $if_bond $if_vf $if_eth
fi

if [ ! -f "${SYSCONFDIR}/ifcfg-$if_vf" ]; then
  logger -s -t $LOGNAME -p info "Creating bonding slave config for $if_vf"
  write_bond_slave_config $if_vf
fi

# Write config for the eth interface even if there is a configuration file.
# It's most likely a DHCP one which won't work with bonding setup.
logger -s -t $LOGNAME -p info "Creating bonding slave config for $if_eth"
write_bond_slave_config $if_eth

# if wicked is running, tell it bring the interface up
if systemctl is-active wickedd.service ; then
	/usr/sbin/wicked ifup $if_bond 2>&1 | logger -s -t $LOGNAME -p info
fi

exit 0
