#!/bin/sh/
#
# playbook_builder
#
# Copyright (C) 2022 by University of Southern California
# Written by ASM Rizvi<asmrizvi@usc.edu>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License,
# version 2, as published by the Free Software Foundation.
# 
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
#

function usage()
{
    echo "
NAME: 
    playbook_builder - Make connections to different anycast sites, announce different routing configurations, run ping measurements, and capture the packet traces for each site.
DESCRIPTION:
    This tool takes input from users about the anycast setup. Then it
    makes connections to different anycast sites, announces different 
    routing configurations, run the ping measurement, and capture the 
    packet traces. This script makes announcements for both positive 
    and negative prepending (upto 3 times). 
    
    This script is particularly written for Peering testbed. However, 
    it can be used for other anycast setup. In other setups, an
    operator needs to modify the way that we use to make connections 
    to different sites. At the same time, an operator needs to change 
    the format of the announcements. 
    
    This script will capture the ping measurement replies in pcap format, 
    and these files in the given directory. These files can be used later 
    to generate the playbook. This script assumes the replies are captured 
    in a single machine (based on peering). If we want to capture at different 
    sites, we need to run tcpdump at individual site or we can forward the 
    traffic towards a single controller machine.
    
    This program requires verfploeter/pinger tool to make the ping measurement: 
    https://ant.isi.edu/software/verfploeter/pinger/index.html.
    This program also requires a recent hitlist that can be requested using 
    the ANT dataset page: https://ant.isi.edu/datasets/all.html
    
Usage: 
    playbook_builder --numbers=NO_OF_SITES --sites=SITE_LIST --prefix=ANNOUNCED_PREFIX --peering=PEERING_DIRECTORY --dest=DEST_DIRECTORY --pinger=PINGER_DIR --source=PINGER_SOURCE_ADDRESS [options]
    
Options:
    --help             Prints help information
    --interface        Interface to be used by pinger, default is the interface for the first site
    --forward          IP to forward traffic, must match the interface, default is the address for the first site
    --iplist           Hitlist file. Default is ip_list.txt.

Args:
    --numbers <NUMBER>        Number of anycast sites
    --sites <LIST>            List of sites separated by comma
    --prefix <PREFIX>         IP prefix for announcement
    --peering <DIRECTORY>     Peering directory
    --dest <DIRECTORY>        Destination to keep the captured files
    --pinger <DIRECTORY>      pinger directory
    --source <ADDRESS>        pinger source address
"
}

GET_NAME(){
	if [[ "$1" = "AMS" ]]; then
		retval="amsterdam01"
	fi

	if [[ "$1" = "BOS" ]]; then
		retval="neu01"
	fi

	if [[ "$1" = "MTG" ]]; then
		retval="ufms01"
	fi

	if [[ "$1" = "SEA2" ]]; then
		retval="uw01"
	fi

	if [[ "$1" = "LAX" ]]; then
		retval="isi01"
	fi

	if [[ "$1" = "GSP" ]]; then
		retval="clemson01"
	fi

	if [[ "$1" = "ATL" ]]; then
		retval="gatech01"
	fi

	if [[ "$1" = "ATH" ]]; then
		retval="grnet01"
	fi

	if [[ "$1" = "PHX" ]]; then
		retval="phoenix01"
	fi

	if [[ "$1" = "SLC" ]]; then
		retval="utah01"
	fi

	if [[ "$1" = "CNF" ]]; then
		retval="ufmg01"
	fi

	if [[ "$1" = "MSN" ]]; then
		retval="wisc01"
	fi

	if [[ "$1" = "SEA1" ]]; then
		retval="seattle01"
	fi
}

GET_INTERFACE(){
	if [[ "$1" = "AMS" ]]; then
		retval="tap5"
	fi

	if [[ "$1" = "BOS" ]]; then
		retval="tap14"
	fi

	if [[ "$1" = "MTG" ]]; then
		retval="tap18"
	fi

	if [[ "$1" = "SEA2" ]]; then
		retval="tap10"
	fi

	if [[ "$1" = "LAX" ]]; then
		retval="tap2"
	fi

	if [[ "$1" = "GSP" ]]; then
		retval="tap16"
	fi

	if [[ "$1" = "ATL" ]]; then
		retval="tap6"
	fi

	if [[ "$1" = "ATH" ]]; then
		retval="tap9"
	fi

	if [[ "$1" = "PHX" ]]; then
		retval="tap4"
	fi

	if [[ "$1" = "SLC" ]]; then
		retval="tap17"
	fi

	if [[ "$1" = "CNF" ]]; then
		retval="tap7"
	fi

	if [[ "$1" = "MSN" ]]; then
		retval="tap11"
	fi

	if [[ "$1" = "SEA1" ]]; then
		retval="tap1"
	fi
}

GET_ADDRESS(){
	if [[ "$1" = "AMS" ]]; then
		retval="100.69.128.1"
	fi

	if [[ "$1" = "BOS" ]]; then
		retval="100.78.128.1"
	fi

	if [[ "$1" = "MTG" ]]; then
		retval="100.82.128.1"
	fi

	if [[ "$1" = "SEA2" ]]; then
		retval="100.74.128.1"
	fi

	if [[ "$1" = "LAX" ]]; then
		retval="100.66.128.1"
	fi

	if [[ "$1" = "GSP" ]]; then
		retval="100.80.128.1"
	fi

	if [[ "$1" = "ATL" ]]; then
		retval="100.70.128.1"
	fi

	if [[ "$1" = "ATH" ]]; then
		retval="100.73.128.1"
	fi

	if [[ "$1" = "PHX" ]]; then
		retval="100.68.128.1"
	fi

	if [[ "$1" = "SLC" ]]; then
		retval="100.81.128.1"
	fi

	if [[ "$1" = "CNF" ]]; then
		retval="100.71.128.1"
	fi

	if [[ "$1" = "MSN" ]]; then
		retval="100.75.128.1"
	fi

	if [[ "$1" = "SEA1" ]]; then
		retval="100.65.128.1"
	fi
}

IP_LIST="ip_list.txt"
while [ "$1" != "" ]; do
    PARAM=`echo $1 | awk -F= '{print $1}'`
    VALUE=`echo $1 | awk -F= '{print $2}'`
    case $PARAM in
        -h | --help)
            usage
            exit
            ;;
        --numbers)
            N_SITES=$VALUE
            ;;
        --sites)
            SITES=$VALUE
            SITE_LIST=(${SITES//,/ })
            SITE_CODE_TEMP=${SITE_LIST[0]}
            GET_INTERFACE $SITE_CODE_TEMP
            SOURCE_INTERFACE=$retval
            GET_ADDRESS $SITE_CODE_TEMP
            FORWARD_IP=$retval
            
            ;;
        --prefix)
            PREFIX=$VALUE
            ;;
        --peering)
            PEERING_DIR=$VALUE
            ;;
        --dest)
            DEST_DIR=$VALUE
            ;;
        --pinger)
            PINGER_DIR=$VALUE
            ;;
        --interface)
            SOURCE_INTERFACE=$VALUE
            ;;
        --forward)
            FORWARD_IP=$VALUE
            ;;
        --source)
            PINGER_SOURCE=$VALUE
            ;;
        --iplist)
            IP_LIST=$VALUE
            ;;
        *)
            echo "ERROR: unknown parameter \"$PARAM\""
            usage
            exit 1
            ;;
    esac
    shift
done

if [ "$EUID" -ne 0 ]
  then echo "Please run as root"
  exit
fi

#N_SITES=$1
#SITES=$2
#SITE_LIST=(${SITES//,/ })
#PREFIX=$3
#PEERING_DIR=/nfs/lander/working/asmrizvi/code/peering/client/
#SOURCE_IP=100.69.128.1
#SOURCE_INTERFACE=tap5

YEAR=$(date +"%Y")
MONTH=$(date +"%m")
DAY=$(date +"%d")
#YEAR=2019
#MONTH=10
#DAY=28
DATE=$YEAR-$MONTH-$DAY
#DEST_DIR=/nfs/landerR04/traces/verfploeter/broot_verfploeter/Peering/Peering_Mapping/2019/
#PINGER_DIR=/nfs/lander/working/asmrizvi/code/peering/pinger-pinger.v0.4.1-alpha/target/release/

#ip route add table 200 to default via ${FORWARD_IP} dev $SOURCE_INTERFACE
#ip rule add from ${PREFIX} table 200 priority 1

if [[ -z "$N_SITES" || -z "$SITES" || -z "$PREFIX" || -z "$PEERING_DIR" || -z "$DEST_DIR" || -z "$PINGER_DIR" || -z "$SOURCE_INTERFACE" || -z "$FORWARD_IP" || -z "$PINGER_SOURCE" ]]; then
    usage
    exit 1
fi

echo $N_SITES"\t"$SITES"\t"$PREFIX"\t"$PEERING_DIR"\t"$DEST_DIR"\t"$PINGER_DIR"\t"$SOURCE_INTERFACE"\t"$FORWARD_IP"\t"$PINGER_SOURCE"\t"$IP_LIST

cd $PEERING_DIR

BGP_ANNOUNCEMENT="./peering bgp start"
for ((index=0;index<$N_SITES;index++));
do
	GET_NAME ${SITE_LIST[$index]}
	CURRENT_SITE=$retval
	echo "VPN connection made: "$CURRENT_SITE"..."
	./peering openvpn up $CURRENT_SITE
	BGP_ANNOUNCEMENT=$BGP_ANNOUNCEMENT" "$CURRENT_SITE
done

echo $BGP_ANNOUNCEMENT"..."
eval $BGP_ANNOUNCEMENT

for ((index=0;index<$N_SITES;index++));
do
	SITE_CODE=${SITE_LIST[$index]}
	GET_NAME $SITE_CODE
	CURRENT_SITE=$retval
	for ((pr_index=0;pr_index<=3;pr_index++));
	do
		OUTPUT_DIR=$DEST_DIR$YEAR-$MONTH-$DAY-$SITES
		if [ $pr_index -ne 0 ]; then
 			OUTPUT_DIR=$OUTPUT_DIR-$SITE_CODE$pr_index
		fi
		if [ ! -d ${OUTPUT_DIR} ] 
		then
			mkdir $OUTPUT_DIR
			chmod -R 777 $OUTPUT_DIR
		else
			continue
		fi

		echo "Directory made: "$OUTPUT_DIR"..."

		for ((j=0;j<$N_SITES;j++));
		do
			SITE_CODE_TEMP=${SITE_LIST[$j]}
			GET_NAME $SITE_CODE_TEMP
			CURRENT_SITE_TEMP=$retval
			cd $PEERING_DIR
			if [ $pr_index -eq 0 ]
			then
				echo "Announcing base case: "$CURRENT_SITE_TEMP"..."
				./peering prefix announce -m $CURRENT_SITE_TEMP $PREFIX
			else
				if [ $CURRENT_SITE_TEMP == $CURRENT_SITE ]
				then
					echo "Announcing prepended: "$CURRENT_SITE_TEMP"-"$pr_index"..."
					./peering prefix announce -m $CURRENT_SITE_TEMP -P $pr_index $PREFIX
				else
					echo "Announcing prepended: "$CURRENT_SITE_TEMP"..."
					./peering prefix announce -m $CURRENT_SITE_TEMP $PREFIX
				fi
			fi
		done

		echo "BGP announcement done. Waiting for 20 mins...."
		sleep 1200
		echo "Wait is done...Time to play the game..."

		for ((j=0;j<$N_SITES;j++));
		do
			SITE_CODE_TEMP=${SITE_LIST[$j]}
			GET_INTERFACE $SITE_CODE_TEMP
			CURRENT_INTERFACE=$retval
			echo "Starting TCPdump process..."
			tcpdump -i $CURRENT_INTERFACE icmp and dst ${PINGER_SOURCE} -w $OUTPUT_DIR/$DATE-$SITE_CODE_TEMP.pcap &
		done

		sleep 20
		ip route add table 200 to default via $FORWARD_IP dev $SOURCE_INTERFACE
		ip rule add from ${PREFIX} table 200 priority 1
		cd $PINGER_DIR
		echo "Starting pinger..."
		cat ${IP_LIST} | ./pinger -s ${PINGER_SOURCE} -r 5000 -i 14001
		echo "Pinger done..."
		sleep 180
		# sh load_measurement.sh $N_SITES $SITES $OUTPUT_DIR $DATE
		pkill -9 tcpdump
	done
done

for ((index=0;index<$N_SITES;index++));
do
	SITE_CODE=${SITE_LIST[$index]}
	GET_NAME $SITE_CODE
	CURRENT_SITE=$retval

	for ((pr_index=1;pr_index<=3;pr_index++));
	do
		OUTPUT_DIR=$DEST_DIR$YEAR-$MONTH-$DAY-$SITES
		for ((j=0;j<$N_SITES;j++));
		do
			SITE_CODE_TEMP=${SITE_LIST[$j]}
			GET_NAME $SITE_CODE_TEMP
			CURRENT_SITE_TEMP=$retval
			cd $PEERING_DIR
			if [ $CURRENT_SITE_TEMP != $CURRENT_SITE ]
			then
				OUTPUT_DIR=$OUTPUT_DIR-$SITE_CODE_TEMP$pr_index
				echo "Announcing negative prepending: "$CURRENT_SITE_TEMP"-"$pr_index"..."
				./peering prefix announce -m $CURRENT_SITE_TEMP -P $pr_index $PREFIX
			else
				echo "Announcing site with no negative: "$CURRENT_SITE_TEMP"..."
				./peering prefix announce -m $CURRENT_SITE_TEMP $PREFIX
			fi
		done

		if [ ! -d ${OUTPUT_DIR} ] 
		then
			echo "Creating directory---"$OUTPUT_DIR
			mkdir $OUTPUT_DIR
			chmod -R 777 $OUTPUT_DIR
		else
			continue
		fi

		echo "BGP announcement done. Waiting for 20 mins...."
		sleep 1200
		echo "Wait is done...Time to play the game..."

		for ((j=0;j<$N_SITES;j++));
		do
			SITE_CODE_TEMP=${SITE_LIST[$j]}
			GET_INTERFACE $SITE_CODE_TEMP
			CURRENT_INTERFACE=$retval
			echo "Starting TCPdump process..."
			tcpdump -i $CURRENT_INTERFACE icmp and dst ${PINGER_SOURCE} -w $OUTPUT_DIR/$DATE-$SITE_CODE_TEMP.pcap &
		done

		sleep 20
		ip route add table 200 to default via $FORWARD_IP dev $SOURCE_INTERFACE
		ip rule add from ${PREFIX} table 200 priority 1
		cd $PINGER_DIR
		echo "Starting pinger..."
		cat ${IP_LIST} | ./pinger -s ${PINGER_SOURCE} -r 5000 -i 14001
		echo "Pinger done..."
		sleep 180
		# sh load_measurement.sh $N_SITES $SITES $OUTPUT_DIR $DATE
		pkill -9 tcpdump
	done
done

cd $PEERING_DIR
BGP_ANNOUNCEMENT="./peering bgp stop"
for ((index=0;index<$N_SITES;index++));
do
	GET_NAME ${SITE_LIST[$index]}
	CURRENT_SITE=$retval
	echo "VPN connection made: "$CURRENT_SITE"..."
	./peering openvpn down $CURRENT_SITE
	BGP_ANNOUNCEMENT=$BGP_ANNOUNCEMENT" "$CURRENT_SITE
done

echo $BGP_ANNOUNCEMENT"..."
eval $BGP_ANNOUNCEMENT
