--- /dev/null
+#!/bin/bash
+#
+# Giovanni Di Stasi
+# Copyright (C) 2009 UniNa
+# $Id$
+#
+# This is a backend script to be used with
+# the vsys system. It allows to define and
+# manage slice-specific routing tables.
+# The routing rules added to these routing
+# tables affect only the respective slices.
+#
+# This script is meant to be called from a
+# fronted script in the slice environment.
+#
+# Fronted usage:
+# sliceip enable <interface>
+# This is the first command to issue; it enables the use
+# of the interface for the slice. This command has to be issued
+# for each interface involved in the slice-specific routing rules.
+#
+# sliceip disable <interface>
+# This is to disable the use of the interface for the slice.
+#
+# sliceip route show
+# This command shows the current routing rules of the
+# slice-specific routing table
+#
+# sliceip route add to <destination> via <gateway> dev <interface>
+# This command adds a rule to reach <destination> through the host
+# <gateway> that can be reached on the interface <interface>
+# ...
+#
+# sliceip in general supports all the commands of the "ip" command of
+# the "iproute2" suite. Refer to ip manpage for further information.
+#
+# Some examples:
+# sliceip route add to 143.225.229.142 via 192.168.8.2 dev ath0
+# sliceip route add default via 10.1.1.1 dev ath0
+#
+# If you want to test the script from the root context you need
+# to call it as vsys would do:
+# sliceip <slice_name>
+# Then you can issue to its standard input the commands previously explained
+# (but you have to remove the initial "sliceip"). Ex.:
+# route add to 143.225.229.142 via 192.168.8.2 dev ath0
+
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+# sliver wich called the script
+sliver=$1
+
+#files used
+RT_TABLES="/etc/iproute2/rt_tables"
+INT_FILE="/tmp/slcroute_ifns"
+
+# routing tables from 100 to 255 are used
+FIRST_TABLE=100
+
+DEBUG=0
+
+#this script can also work on a Linux machine, in wich case
+#it enables user-specific routing tables
+LINUX_ENV=0 # 0 - Linux host;
+ # does not work for the icmp protocol
+
+PLANET_ENV=1 # 1 - PlanetLab context (slice-specific routing)
+
+#select the PlanetLab environment
+ENVIRONMENT=$PLANET_ENV
+
+
+# enable an interface for the slice specific routing rules
+# and initialise the slice routing table
+function enable_interface(){ # $1 calling sliver; $2 interface to enable
+ local sliver=$1
+ local interface="$2"
+ local ip=`get_address $interface`
+
+ if [[ "" == $ip ]]; then
+ echo "Failed in getting address of $interface"
+ return 1
+ fi
+
+ local nid=`get_nid $sliver`
+
+ local num_active=`get_num_activated $sliver`
+
+ if ! is_active $sliver $interface; then
+
+ if [[ $num_active == 0 ]]; then
+ #define the routing table for the slice and set some iptables rules in order to mark user's packets;
+ create_table $sliver
+ fi
+
+ #Adds an SNAT rule to set the source IP address of packets that are about to go out through $interface.
+ #The kernel sets the source address of packets when the first routing process happens (following the rules
+ #of the main routing table); when the rerouting process happens (following the user/slice specific rules)
+ #the source address is not modified. Consequently, we need to add this rule to change the source ip address
+ #to the $interface source address.
+ exec "iptables -t nat -A POSTROUTING -o $interface -j SNAT --to-source $ip -m mark --mark $nid"
+
+ set_active $sliver $interface $ip
+
+ else
+ local old_ip=`get_ip_from_file $sliver $interface`
+
+ if [[ $old_ip != $ip ]]; then
+ #remove the rule for the old ip
+ exec "iptables -t nat -D POSTROUTING -o $interface -j SNAT --to-source $old_ip -m mark --mark $nid"
+ #insert the new rule
+ exec "iptables -t nat -A POSTROUTING -o $interface -j SNAT --to-source $ip -m mark --mark $nid"
+
+ set_deactivated $sliver $interface $old_ip
+ set_active $sliver $interface $ip
+ fi
+
+
+ fi
+
+}
+
+# disable the interface for the slice-specific routing rules
+function disable_interface(){
+ local sliver=$1
+ local interface=$2
+
+ local ip=`get_ip_from_file $sliver $interface`
+
+ local nid=`get_nid $sliver`
+
+ if is_active $sliver $interface >/dev/null 2>&1; then
+ exec "iptables -t nat -D POSTROUTING -o $interface -j SNAT --to-source $ip -m mark --mark $nid"
+
+ local num_ifn_on=`get_num_activated $sliver`
+
+ if [[ $num_ifn_on == 1 ]]; then
+ delete_table $sliver
+ fi
+
+ set_deactivated $sliver $interface
+ fi
+
+}
+
+# wrapper function used to execute system commands
+function exec(){
+ local command=$1
+
+ if ! [[ $command ]]; then
+ echo "Error in exec. No argument."
+ exit 1
+ else
+ if ! $command; then
+ if [[ $DEBUG == 1 ]]; then echo "Error executing \"$1\""; fi
+ echo EOF
+ exit 1
+ fi
+ fi
+
+}
+
+# decides wich id to use for the slice routing table
+function get_table_id(){
+ local sliver=$1
+
+ k=$FIRST_TABLE
+
+ while [[ $k < 255 ]] && grep $k $RT_TABLES >/dev/null 2>&1 ; do
+ k=$((k+1))
+ done
+
+ if [[ $k == 255 ]]; then
+ logm "No routing tables available. Exiting."
+ return 1
+ fi
+
+ echo $k
+}
+
+
+# create the slice-specifig routing table
+function create_table(){
+ local sliver=$1
+
+ local table_name=`get_table_name $sliver`
+ local table_id=`get_table_id $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if ! grep $table_name $RT_TABLES > /dev/null 2>&1; then
+ echo "$table_id $table_name" >> $RT_TABLES
+ else
+ echo "WARNING: $table_name routing table already defined."
+ fi
+
+ set_routes $sliver $table_name
+
+ return 0
+}
+
+# delete the slice-specific routing table
+function delete_table(){
+ local sliver=$1
+
+ local table_name=`get_table_name $sliver`
+ local table_id=`get_nid $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if ! grep $table_name $RT_TABLES > /dev/null 2>&1; then
+ return 1
+ else
+ exec "ip route flush table $table_name" >/dev/null 2>&1
+ unset_routes $sliver $table_name
+ remove_line "$RT_TABLES" "$table_name"
+ fi
+
+ return 0
+}
+
+# remove a line from a file
+function remove_line(){
+ local filename=$1
+ local regex=$2
+
+ #remove interface line from the file
+
+ exec "sed /${regex}/d $filename" > $filename.tmp
+ exec "mv $filename.tmp $filename"
+
+
+}
+
+# get the slice-specific routing table name
+function get_table_name(){
+ local sliver=$1;
+ echo "${sliver}_slcip"
+}
+
+function clean_iproute_conf(){
+ while grep "slcip" $RT_TABLES >/dev/null 2>&1; do
+ remove_line $RT_TABLES "slcip"
+ done
+
+ rm ${INT_FILE}*
+
+}
+
+#get slice network id
+function get_nid(){
+ id -u ${1}
+}
+
+# set the firewall rules. Mainly, it asks VNET+ to set the netfilter mark of packets belonging to the slice to the slice-id
+# and then associates those packets with the routing table allocated for that slice.
+function set_routes(){
+ local sliver=$1
+ local table_name=$2
+
+ local sliver_nid=`get_nid $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if [ $ENVIRONMENT == $PLANET_ENV ]; then
+ #Linux kernel triggers a rerouting process, wich is needed to perfom slice-specific routing,
+ #if it sees that the netfilter mark has been altered in the iptables mangle chain.
+ #As VNET+ sets the netfilter mark of some packets in advance (to the slice-id value) before they enter the iptables mangle chain,
+ #we need to change it here (otherwise the rerouting process is not triggered for them).
+ exec "iptables -t mangle -A OUTPUT -m mark --mark $sliver_nid -j MARK --set-mark $temp_nid"
+
+ #Here we ask VNET+ to set the netfilter mark for the remaining packets (to the slice-id)
+ exec "iptables -t mangle -A OUTPUT -j MARK -m mark ! --mark $temp_nid --copy-xid 0x00"
+ elif [ $ENVIRONMENT == $LINUX_ENV ]; then
+ #the same in the case of a "plain" Linux box. In this case we do not use VNET+ but
+ #the owner module of iptables.
+ exec "iptables -t mangle -A OUTPUT -m owner --uid-owner $sliver_nid -j MARK --set-mark $sliver_nid"
+ fi
+
+ #Here the netfilter mark is restored to the slice-id value for the "strange packets"
+ exec "iptables -t mangle -I POSTROUTING 1 -m mark --mark $temp_nid -j MARK --set-mark $sliver_nid"
+
+ #Set the routing for the slice to be applied following the rules in $table_name"
+ #for the slice packets...
+ exec "ip rule add fwmark $sliver_nid table $table_name"
+ #...and for the "strange packets"
+ exec "ip rule add fwmark $temp_nid table $table_name"
+
+ exec "ip route flush cache" >/dev/null 2>&1
+}
+
+# removes the firewall rules.
+function unset_routes(){
+ local sliver=$1
+ local table_name=$2
+
+ local sliver_nid=`get_nid $sliver`
+ local temp_nid=`get_temp_nid $sliver`
+
+ if [ $ENVIRONMENT == $PLANET_ENV ]; then
+ #removes the rules for the netfilter marks (for the "strange packets")
+ exec "iptables -t mangle -D OUTPUT -m mark --mark $sliver_nid -j MARK --set-mark $temp_nid"
+
+ #removes the rules that asks VNET+ to set the netfilter mark to the slice-id
+ exec "iptables -t mangle -D OUTPUT -m mark ! --mark $temp_nid -j MARK --copy-xid 0x00"
+ elif [ $ENVIRONMENT == $LINUX_ENV ]; then
+ #removes the rules that asks the owner module of iptables to set the netfilter mark to the user-id
+ exec "iptables -t mangle -D OUTPUT -m owner --uid-owner $sliver_nid -j MARK --set-mark $sliver_nid"
+ fi
+
+ exec "iptables -t mangle -D POSTROUTING -m mark --mark $temp_nid -j MARK --set-mark $sliver_nid"
+
+ exec "ip rule del fwmark $temp_nid table $table_name"
+ exec "ip rule del fwmark $sliver_nid table $table_name"
+
+ exec "ip route flush cache"
+
+}
+
+# get the ip address of an interface
+function get_address(){
+ local interface=$1
+ local ip=""
+
+ ip=`ifconfig $interface | grep inet\ addr | cut -d ":" -f 2 | cut -d " " -f 1`;
+
+ if valid_dotted_quad $ip; then
+ echo $ip;
+ else
+ echo "";
+ fi
+
+}
+
+# get the temporary mark to be applied to the slice packets
+function get_temp_nid(){
+ local sliver_nid=`get_nid $1`
+ local temp_nid=$((0x20000+$sliver_nid))
+ echo $temp_nid
+}
+
+# log function
+function logm(){
+ logger $1
+}
+
+# get the name of the filename in wich we store information about
+# the interfaces in use by the user
+function get_filename_sliver(){
+ local sliver=$1
+ echo "${INT_FILE}-$sliver"
+}
+
+function set_active(){
+ local sliver=$1
+ local interface=$2
+ local ip=$3
+
+ local filename="${INT_FILE}-$sliver"
+
+ echo "$interface $ip" >> $filename
+
+}
+
+function set_deactivated(){
+
+ local sliver=$1
+ local interface=$2
+
+ local filename=`get_filename_sliver $sliver`
+
+ remove_line $filename $interface
+}
+
+function is_active(){
+ local sliver=$1
+ local interface=$2
+
+ local filename=`get_filename_sliver $sliver`
+
+ if grep $interface $filename >/dev/null 2>&1; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function get_num_activated(){
+ local sliver=$1
+
+ local filename=`get_filename_sliver $sliver`
+
+ if ! [ -e $filename ]; then
+ echo 0;
+ else
+ wc -l $filename | cut -f 1 -d " ";
+ fi
+}
+
+
+function get_ip_from_file(){
+ local sliver=$1
+ local interface=$2
+
+ local filename=`get_filename_sliver $sliver`
+
+ cat $filename | grep $interface | cut -d " " -f 2
+}
+
+
+
+# checks ip addresses
+function valid_dotted_quad(){
+ oldIFS=$IFS
+ IFS=.
+ set -f
+ set -- $1
+ if [ $# -eq 4 ]
+ then
+ for seg
+ do
+ case $seg in
+ ""|*[!0-9]*) return 1; break ;; ## Segment empty or non-numeric char
+ *) [ $seg -gt 255 ] && return 2 ;;
+ esac
+ done
+ else
+ return 3 ## Not 4 segments
+ fi
+ IFS=$oldIFS
+ set +f
+ return 0;
+}
+
+
+# BEGIN
+# the script starts here
+
+if [[ $sliver == "" ]]; then
+ echo "I need the first argument (the sliver name)";
+ exit 1
+fi
+
+# read a line from the vsys pipe
+read line
+
+# separates the first word of the line from the others
+command=`echo ${line%% *}`
+rest=`echo ${line#* }`
+
+case "$command" in
+ enable)
+ logger "slcip command received from $sliver: $line"
+ enable_interface $sliver "$rest"
+ ;;
+
+ disable)
+ logger "slcip command received from $sliver: $line"
+ disable_interface $sliver "$rest"
+ ;;
+
+ *)
+ logger "slcip command received from $sliver: $line"
+ table_sliver=`get_table_name $sliver`
+
+ # adds the rule
+ if ! grep "$table_sliver" $RT_TABLES >/dev/null 2>&1; then
+ echo "Error. The slice routing table is not defined. Execute sliceip enable <interface>."
+ else
+ exec "ip $line table $table_sliver"
+ fi
+ ;;
+
+esac
+
+# make the frontend quit
+echo "EOF"
+
+exit 0
+
+
+