#!/bin/bash

### Wrapper to create firewall rules in OpenFlow
# v0.1.0 2012 Sergio Kviato sergey.kviato@onapp.com
#
# --add/del action to do, add or remove rule
# --int interface name
# --dst-port dest port
# --proto proto (tcp,udp,icmp)
# --cmd command, what to do with packet (accept, drop)
# --src-address the source address
# --dst-address destination address. Binded to VM interface
# -4 for IPv4 (default)
# -6 for IPv6
# --prio priority for rules
# --clear clear all ruls for dedicated interface

### Setup ###
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"

ACTION=""
INTERFACE=""
SRC_ADDRESS=""
DST_ADDRESS=""
TP_DST=""
DST_PORT=""
NW_PROTO=""
PROTO_NAME=""
COMMAND=""
CMD=""
CLEAR=0

# highest priority by default
PRIORITY="32700"
DL_TYPE="0x0800"

### The Code ###
# Check if there any arguments
if [ -z $1 ]; then
 echo "Just what do you think you're doing, there no arguments"
exit 1
fi

# Process command line arguments
for arg in {1..20}
do
    case "${!arg}" in
	"--del")
	ACTION="del-flows"
	;;
	"--add")
	ACTION="add-flow"
	;;
	"--int") 
	((argn=arg+1))
	INTERFACE=${!argn}
	;;
	"--src-address")
	((argn=arg+1))
	SRC_ADDRESS=${!argn}
	;;
	"--dst-address")
	((argn=arg+1))
	DST_ADDRESS=${!argn}
	;;
	"--dst-port")
	((argn=arg+1))
	DST_PORT=${!argn}
	;;
	"--proto")
	((argn=arg+1))
	PROTO_NAME=${!argn}
	;;
	"--cmd")
	((argn=arg+1))
	CMD=${!argn}
	;;
	"-6")
	((argn=arg+1))
	DL_TYPE="0x86dd"
	;;
	"--prio")
	((argn=arg+1))
	((PRIORITY=32700-${!argn}))
	;;
	"--clear")
	((argn=arg+1))
	CLEAR=1
	ACTION="del-flows"
	;;
#	*)
#	echo "Are you trying to run $0 without valid options? You're going to find that rather difficult."
#	exit 1
#	;;
    esac
done

if [ -z "$INTERFACE" ]; then
	echo "You must specify interface name."
	exit 1
fi

if [ -z "$DST_ADDRESS" ]; then
    echo "Just what do you think you're doing, you need to specify DESTINATION ADDRESS."
    exit 1
fi

# Find Switch name by interface name
SWITCH=$($OVSVSCTL port-to-br $INTERFACE)
#PORT=$($OVSVSCTL -- get Interface $INTERFACE ofport)

# Just in case we want to clear all rules for dedicated IP
if [ "$CLEAR" -eq 1 ]; then
    for rule in `$OVSOFCTL dump-flows $SWITCH | grep "nw_dst=$DST_ADDRESS" | sed 's/.*priority=[0-9]*,//g;s/actions=[[:alpha:]]//g'`
    do
	$OVSOFCTL $ACTION $SWITCH "$rule"
    done
exit 0
fi

case "$CMD" in
	[Aa][Cc][Cc][Ee][Pp][Tt])
	COMMAND="actions=normal"
	;;
	[Dd][Rr][Oo][Pp])
	COMMAND="actions=drop"
	;;
esac

case "$PROTO_NAME" in 
	[Tt][Cc][Pp])
	NW_PROTO=6
	;;
	[Uu][Dd][Pp])
	NW_PROTO=17
	;;
        [Ii][Cc][Mm][Pp])
	if [ "$DL_TYPE" == "0x86dd" ]; then
		NW_PROTO=58
	else 
		NW_PROTO=1
	fi
        ;;
esac

if [ -n "$DST_PORT" ]; then
    TP_DST="tp_dst=$DST_PORT"
fi

if [ -n "$SRC_ADDRESS" ]; then
    SRC_ADDRESS="nw_src=$SRC_ADDRESS"
fi

if [ "$PRIORITY" -lt 200 ]; then
	echo "You trying to set to high PRIORITY number $PRIORITY. You're going to find that rather difficult."
	echo "Rule does not setted up."
	exit 1
fi

RULE="priority=$PRIORITY dl_type=$DL_TYPE nw_proto=$NW_PROTO $SRC_ADDRESS nw_dst=$DST_ADDRESS $TP_DST $COMMAND"

$OVSOFCTL $ACTION $SWITCH "$RULE"

exit 0
