#!/bin/sh
# Univention Virtual Machine Manager KVM Node
#  VLAN init script
#
# Most parts of this script are taken from the xen bridging scripts.
# Details to the copyright can be found under
# /usr/share/doc/univention-virtual-machine-manager-node-kvm/copyright

### BEGIN INIT INFO
# Provides:          univention-virtual-machine-manager-node-vlan
# Required-Start:    $network $local_fs univention-virtual-machine-manager-node-kvm
# Required-Stop:
# Should-Start:      $named
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Univention Virtual Machine Manager VLAN initialisation
# Description:       Create a bridging network interface on secondary and VLAN Interfaces
### END INIT INFO

# Usage: setup_bridge_port device
# Configure interfaces which act as pure bridge ports:
setup_bridge_port() {
    local dev="$1"

    # take interface down ...
    ip link set ${dev} down

    # ... and configure it
    ip addr flush ${dev}
}

# Usage: create_bridge bridge
# Create named bridge
create_bridge () {
    local bridge=$1

    # Don't create the bridge if it already exists.
    if [ ! -e "/sys/class/net/${bridge}/bridge" ]; then
	brctl addbr ${bridge}
	brctl stp ${bridge} off
	brctl setfd ${bridge} 0
    fi
}

# Usage: add_to_bridge bridge device
# Add device to existing bridge
add_to_bridge () {
    local bridge=$1
    local dev=$2

    # Don't add $dev to $bridge if it's already on a bridge.
    if [ -e "/sys/class/net/${bridge}/brif/${dev}" ]; then
	ip link set ${dev} up || true
	return
    fi
    brctl addif ${bridge} ${dev}
    ip link set ${dev} up
}

# Usage: link_exists dev
# Returns 0 if the interface named exists (whether up or down), 1 otherwise.
#
link_exists()
{
    local dev=$1
    if ip link show "${dev}" >/dev/null 2>/dev/null
    then
        return 0
    else
        return 1
    fi
}

# Usage: add_to_bridge2 bridge device
# adds device to bridge but waits for device to be in running state first
add_to_bridge2() {
    local bridge=$1
    local dev=$2
    local maxtries=10

    echo -n "Waiting for ${dev} to negotiate link."
    ip link set ${dev} up
    for i in `seq ${maxtries}` ; do
	if ifconfig ${dev} | grep -q RUNNING ; then
	    break
	else
	    echo -n '.'
	    sleep 1
	fi
    done

    if [ ${i} -eq ${maxtries} ] ; then echo -n '(link isnt in running state)' ; fi
    echo

    add_to_bridge ${bridge} ${dev}
}

# Usage: load_mod_8021q
# Check for kernel module 8021q and load if not loaded
load_mod_8021q () {
    if ! lsmod | grep -q '8021q' ; then
       if ! modprobe 8021q ; then 
          return 1;
       fi
    fi
    return 0;
}

# Usage: show_status
# Print bridges and routes.
show_status () {

    echo '============================================================'
    echo ' '
    brctl show 
    echo ' '
    ip route list
    echo ' '
    route -n
    echo '============================================================'
}

######################################################################
#
# Start-Stop-Routines.
#

op_start () {
    local dev=$1
    local vlan=$2
    local bridge=lan${vlan}

    if [ $vlan -le 1 ] ; then
       # special case: vlan1 = network interface (untagged)
       local iface=$dev
    else
       # normal case: vlan > 1; extra interface
    
       # test for 802.1q
       if ! load_mod_8021q ; then
          # could not load module
          [ -x /usr/bin/logger ] && /usr/bin/logger "univention-virtual-machine-manager-node-vlan: could not load module 802.1q; not started"
          exit
       fi

       # set vlan-name-type
       vconfig set_name_type VLAN_PLUS_VID

       # create vlan if not existing
       if ! grep "${dev}" /proc/net/vlan/config | egrep -q "| +${vlan} +|" ; then
          vconfig add ${dev} ${vlan}
       fi
       local iface=`grep "${dev}" /proc/net/vlan/config | egrep "| +${vlan} +|" | cut -d ' ' -f 1`
    fi

    # create bridge and add interface
    create_bridge $bridge
    add_to_bridge $bridge $iface

    if [ ${antispoof} = 'yes' ] ; then
	antispoofing ${dev}
    fi
    # finally, set bridge up
    ip link set $bridge up
}

op_stop () {
    local dev=$1
    local vlan=$2
    local bridge=lan${vlan}
 
    if ! link_exists "$bridge"; then
	return
    fi

    if [ $vlan -le 1 ] ; then
       # special case: vlan1 = network interface (untagged)
       local iface=$dev
    else
       # normal case: vlan > 1; extra interface
       local iface=`grep "${dev}" /proc/net/vlan/config | egrep "| +${vlan} +|" | cut -d ' ' -f 1`
    fi

    brctl delif ${bridge} ${iface}
    brctl delbr ${bridge}
}

######################################################################################
#
#  This is where all the things start
#

command=$1
case "$command" in
    start)
        # check ucr autostart setting
        if [ -f "/usr/share/univention-config-registry/init-autostart.lib" ]; then
            source "/usr/share/univention-config-registry/init-autostart.lib"
            check_autostart univention-virtual-machine-manager-node-kvm uvmm/kvm/bridge/autostart
        fi

        antispoof=${antispoof:-no}   # set iptables to forward to the bridge?
	    op_start eth1 1
        op_start eth1 1720
        ;;
    stop)
	    op_stop eth1 1
        op_stop eth1 1720
	    ;;
    status)
	    show_status 
	    ;;
    *)
	    echo "Unknown command: $command" >&2
	    echo 'Valid commands are: start, stop, status' >&2
	    exit 1
esac
