#!/bin/bash
#============================================================================
# /etc/xen/vif-ovs
#
# Script for configuring a vif in OVS mode.
# The hotplugging system will call this script if it is specified either in
# the device configuration given to Xend, or the default Xend configuration
# in /etc/xen/xend-config.sxp.  If the script is specified in neither of those
# places, then this script is the default.
#
# Usage:
# vif-ovs (add|remove|online|offline)
#
# Environment vars:
# vif         vif interface name (required).
# XENBUS_PATH path to this device's details in the XenStore (required).
#
# Read from the store:
# bridge  bridge to add the vif to (optional).  Defaults to searching for the
#         bridge itself.
# ip      list of IP networks for the vif, space-separated (optional).
#
# up:
# Enslaves the vif interface to the bridge and adds iptables rules
# for its ip addresses (if any).
#
# down:
# Removes the vif interface from the bridge and removes the iptables
# rules for its ip addresses (if any).
#============================================================================

dir=$(dirname "$0")
. "$dir/vif-common.sh"

OVSVSCTL=$(whereis -b ovs-vsctl | awk '{print $2}')
OVSOFCTL=$(whereis -b ovs-ofctl | awk '{print $2}')
RUNPATH="/var/run/openvswitch"
OVSVSCTL="$OVSVSCTL --db=unix:$RUNPATH/db.sock"

bridge=${bridge:-}
mac=""
intname=""
bridge=$(xenstore_read_default "$XENBUS_PATH/bridge" "$bridge")
mac=$(xenstore_read_default "$XENBUS_PATH/mac" "$mac")
intname=$(xenstore_read_default "$XENBUS_PATH/vifname" "$intname")

if [ -z "$bridge" ]; then
    fatal "Could not find bridge, none was specified"
fi

if [ -z "$mac" ]; then
    fatal "Cold not find mac address for interface"
fi

if [ -z "$intname" ]; then
    fatal "Cold not find interface name"
fi

RET=0
ip link show $bridge 1>/dev/null 2>&1 || RET=1
if [ "$RET" -eq 1 ]; then
    fatal "Could not find bridge device $bridge"
fi

case "$command" in
    online)
	setup_bridge_port "$vif"
	add_to_bridge "$bridge" "$vif"
	# Just check in case if VM rebooted inside
	# 2 loops, first to check IP spoof rules
	# second to check ARP spoof rules
	PORT_IN_FACT=$($OVSVSCTL -- get Interface $intname ofport 2>/dev/null)
	$OVSOFCTL dump-flows "$bridge" | grep "dl_src=$mac" | awk '{print $6}' | while read rule
	do
	RULE_IP=`echo $rule | cut -d, --fields=1,2,4,5`

	if [ -z "$RULE_IP" ]; then
	    break
	fi
	
	# Find current port if present
	PORT_IP=`echo $rule | awk -F, '{print $3}' | awk -F= '{print $2}'`

	    if [ "${PORT_IN_FACT}0" -ne "${PORT_IP}0" ]; then
		# If so, some rules need to change
		# Due to VM rebooted inside
		# Or old rules where not removed properly
		
		# need to reassingn "rule" variable to cut-off priority
		# without this, rule will not much
		rule=`echo $rule | sed 's/priority=[0-9][0-9][0-9][0-9],//'`
		$OVSOFCTL del-flows $bridge "$rule" > /dev/null 2>&1
		$OVSOFCTL add-flow $bridge "${RULE_IP},in_port=${PORT_IN_FACT} action=normal" > /dev/null 2>&1
	    fi

	done
	# Check ARP spoof rules
	$OVSOFCTL dump-flows "$bridge" | grep "arp_sha=$mac" | awk '{print $6}' | while read rule
	do
	RULE_ARP=`echo $rule | cut -d, --fields=1,3,4,5`

	if [ -z "$RULE_ARP" ]; then
	    break
	fi
	
	# Find current port if present
	PORT_ARP=`echo $rule | awk -F, '{print $2}' | awk -F= '{print $2}'`
	
	    if [ "${PORT_IN_FACT}0" -ne "${PORT_ARP}0" ]; then
		# If so, some rules need to change
		# Due to VM rebooted inside
		# Or old rules where not removed properly
		$OVSOFCTL del-flows $bridge "$rule" > /dev/null 2>&1
		$OVSOFCTL add-flow $bridge "${RULE_ARP},in_port=${PORT_IN_FACT} action=normal" > /dev/null 2>&1
	    fi
	done
	
	;;

    offline)
        do_without_error ovs-vsctl del-port "$bridge" "$vif"
        do_without_error ifconfig "$vif" down
        ;;
esac

log debug "Successful vif-bridge $command for $vif, bridge $bridge."
if [ "$command" == "online" ]; then
  success
fi



