From 9bf4755e932e0036db1bc03285e8c2a3b8ed0ede Mon Sep 17 00:00:00 2001 From: Giovanni Di Stasi Date: Tue, 9 Jul 2013 14:29:32 +0200 Subject: [PATCH] vsys for new lxc based planetlab code --- root-context/exec/sliceip.lxc | 368 ++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 root-context/exec/sliceip.lxc diff --git a/root-context/exec/sliceip.lxc b/root-context/exec/sliceip.lxc new file mode 100644 index 0000000..d91a776 --- /dev/null +++ b/root-context/exec/sliceip.lxc @@ -0,0 +1,368 @@ +#!/bin/bash +# +# Giovanni Di Stasi +# +# Copyright (C) 2009-2013 UniNa +# +# 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 +# frontend script in the slice environment. +# +# Fronted usage: +# +# sliceip route show +# Shows the current routing rules of the +# slice-specific routing table +# +# sliceip route add to via dev +# Adds a rule to reach through the host +# that can be reached on the 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 +# sliceip route add to 143.225.229.142 nexthop via 192.168.0.1 dev eth1 \ +# weight 1 src 192.168.0.2 nexthop via 192.168.1.1 dev eth2 weight 1 +# +# sliceip can also be used without a frontend program as follows. +# +# First use cat to show the output: +# cat < /vsys/sliceip.out & +# Then issue a command as, e.g., the following routing rule: +# echo "route add to some_ip via some_other_ip dev eth0" > /vsys/sliceip.in +# +# If you want to test the script from the root context you need +# to call it as vsys would do: +# sliceip +# 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 +# +# A frontend sliceip script can therefore be created as follows: +# #!/bin/bash +# cat < /vsys/sliceip.out & +# echo $* > /vsys/sliceip.in +# +# Notes for PlanetLab developers: +# For sliceip to work correctly it is required that, at boot time +# i) stale entries of /etc/iproute2/rt_tables are removed, i.e. lines that +# contain slcip; ii) /tmp/ is cleaned. + +PATH=/bin:/usr/bin:/sbin:/usr/sbin + +# sliver which called the script +sliver=$1 + +#file used +RT_TABLES="/etc/iproute2/rt_tables" + +# routing tables from 6 to 249 are used +FIRST_TABLE=6 +LAST_TABLE=249 + +DEBUG=0 + + + +# wrapper function used to execute system commands +function exec(){ + local command=$1 + + if ! [[ $command ]]; then + echo "Error in exec. No argument." + else + if ! $command; then + if [[ $DEBUG == 1 ]]; then echo "Error executing \"$1\""; fi + fi + fi + +} + +# Returns the number of routing rules in routing table $table +function get_num_rules(){ + local table=$1 + + ip route show table $table | wc -l + +} + + +# Assign a routing table to the sliver (by creating a mapping in +# /etc/iproute2/rt_tables). +# If all the routing tables are assigned, remove the mappings +# for slivers that do not have rules in their routing +# tables. +function create_table(){ + + local table_sliver=$1 + + #if the table already exists, returns immediately + if grep "$table_sliver" $RT_TABLES >/dev/null 2>&1; then + return 0 + fi + + #... otherwise find a free routing table to assign to the sliver + k=$FIRST_TABLE + while [[ $k -lt $((LAST_TABLE+1)) ]] && grep "$k " $RT_TABLES >/dev/null 2>&1 ; do + k=$((k+1)); + done + + #if all were already assigned, remove unused assignements + if [[ $k == $((LAST_TABLE+1)) ]]; then + k=$FIRST_TABLE + while [[ $k -lt $((LAST_TABLE+1)) ]] && grep "$k " $RT_TABLES >/dev/null 2>&1 ; do + if [[ `get_num_rules $k` == 0 ]]; then + delete_table `cat $RT_TABLES | grep "$k " | cut -d " " -f 2` + fi + k=$((k+1)); + done + + #pick the first that has become available, if any + k=$FIRST_TABLE + while [[ $k -lt $((LAST_TABLE+1)) ]] && grep "$k " $RT_TABLES >/dev/null 2>&1 ; do + k=$((k+1)); + done + + #otherwise give up and return that no table is available + if [[ $k == $((LAST_TABLE+1)) ]]; then + echo "No routing tables available. Exiting." + return 1 + fi + + fi + + echo "$k $table_sliver" >> $RT_TABLES + + set_routes $sliver $table_sliver + + return 0 +} + +# Delete the slice-specific routing table +function delete_table(){ + local table_name=$1 + local sliver=`basename $table_name "_slcip"` + + 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 -i /${regex}/d $filename" +} + +# Get the slice-specific routing table name +function get_table_name(){ + local sliver=$1; + echo "${sliver}_slcip" +} + +# Remove files used by sliceip and the added routing tables +function clean_iproute_conf(){ + while grep "slcip" $RT_TABLES >/dev/null 2>&1; do + remove_line $RT_TABLES "slcip" + done +} + + +# Get sliver's virtual interface +function get_sliver_veth(){ + local sliver=$1 + cat /var/run/libvirt/lxc/$sliver.xml | grep "target dev" | cut -d "=" -f 2 | cut -d "'" -f 2 +} + +function get_sliver_ip(){ + local sliver=$1 + local interface=eth0 + local ip="" + + ip=`echo "ifconfig $interface" | lxcsu $sliver | grep inet\ addr | cut -d ":" -f 2 | cut -d " " -f 1`; + + if valid_dotted_quad $ip; then + echo $ip; + else + echo ""; + fi + +} + + + +# set the firewall rules. +# Basically source routing is enabled. +function set_routes(){ + local sliver=$1 + local table_name=$2 + #local sliver_veth=`get_sliver_veth $sliver` + local sliver_ip=`get_sliver_ip $sliver` + + # Set $table_name as routing table for the sliver + # through source routing + #exec "ip rule add iif $sliver_veth table $table_name" + exec "ip rule add from $sliver_ip table $table_name" + + exec "ip route flush cache" >/dev/null 2>&1 + + #Flush stale routing rules in $table_name + exec "ip route flush table $table_name" +} + + +# Remove the firewall rules. +function unset_routes(){ + local sliver=$1 + local table_name=$2 + #local sliver_veth=`get_sliver_veth $sliver` + local sliver_ip=`get_sliver_ip $sliver` + + + # Unset $table_name as routing table for the sliver + # through source routing + exec "ip rule del from $sliver_ip table $table_name" + + exec "ip route flush cache" >/dev/null 2>&1 +} + + +# 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 + +} + + +# Log function +function logm(){ + logger $1 +} + + + + +# Check an ip address for correcteness +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; +} + +# Check to see if the command start with "route" +function checkCommand(){ + + local cmd="$1" + local first=`echo "$cmd" | awk '{print $1}'` + #local second=`echo $cmd | awk '{print $2}'` + + + if [[ "$first" != "route" ]]; then + echo "Command must start with route." + return 1 + fi + + 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 + +# separate the first two words of the line from the rest +command=`echo $line | awk '{print $1 " " $2}'` +rest=`echo $line | awk '{ for (i = 3; i<=NF; i++) { printf "%s ",$i } }'` + +#rest=`echo ${line#* }` + + + +case "$command" in + enable) + #enable and disable kept for compatibility + logger "sliceip command received from $sliver: $line" + ;; + + disable) + logger "sliceip command received from $sliver: $line" + ;; + + *) + logger "sliceip command received from $sliver: $line" + + #no concurrent executions of sliceip allowed + while ! mkdir /tmp/sliceip.lock >/dev/null 2>&1; do + sleep 0.5 + done + + table_sliver=`get_table_name $sliver` + + #checks the command, creates the routing table and adds the rule + if checkCommand "$command" && create_table $table_sliver; then + + + #add the routing rule - ip is called with the same parameters of sliceip but the indication of + #the table in which the rule is to be inserted is inserted + exec "ip $command table $table_sliver $rest" + + fi + + #remove the lock + rmdir /tmp/sliceip.lock + + ;; + +esac + +exit 0 -- 2.43.0