4 # <giovanni.distasi on the unina.it domain>
5 # Copyright (C) 2009-2013 UniNa
7 # This is a backend script to be used with
8 # the vsys system. It allows to define and
9 # manage slice-specific routing tables.
10 # The routing rules added to these routing
11 # tables affect only the respective slices.
13 # This script is meant to be called from a
14 # frontend script in the slice environment.
19 # Shows the current routing rules of the
20 # slice-specific routing table
22 # sliceip route add to <destination> via <gateway> dev <interface>
23 # Adds a rule to reach <destination> through the host
24 # <gateway> that can be reached on the interface <interface>
27 # sliceip in general supports all the commands of the "ip" command of
28 # the "iproute2" suite. Refer to ip manpage for further information.
31 # sliceip route add to 143.225.229.142 via 192.168.8.2 dev ath0
32 # sliceip route add default via 10.1.1.1 dev ath0
33 # sliceip route add to 143.225.229.142 nexthop via 192.168.0.1 dev eth1 \
34 # weight 1 src 192.168.0.2 nexthop via 192.168.1.1 dev eth2 weight 1
36 # sliceip can also be used without a frontend program as follows.
38 # First use cat to show the output:
39 # cat < /vsys/sliceip.out &
40 # Then issue a command as, e.g., the following routing rule:
41 # echo "route add to some_ip via some_other_ip dev eth0" > /vsys/sliceip.in
43 # If you want to test the script from the root context you need
44 # to call it as vsys would do:
45 # sliceip <slice_name>
46 # Then you can issue to its standard input the commands previously explained
47 # (but you have to remove the initial "sliceip"). Ex.:
48 # route add to 143.225.229.142 via 192.168.8.2 dev ath0
50 # A frontend sliceip script can therefore be created as follows:
52 # cat < /vsys/sliceip.out &
53 # echo $* > /vsys/sliceip.in
55 # Notes for PlanetLab developers:
56 # For sliceip to work correctly it is required that, at boot time
57 # i) stale entries of /etc/iproute2/rt_tables are removed, i.e. lines that
58 # contain slcip; ii) /tmp/ is cleaned.
60 PATH=/bin:/usr/bin:/sbin:/usr/sbin
62 # sliver which called the script
66 RT_TABLES="/etc/iproute2/rt_tables"
68 # routing tables from 6 to 249 are used
76 # wrapper function used to execute system commands
80 if ! [[ $command ]]; then
81 echo "Error in exec. No argument."
84 if [[ $DEBUG == 1 ]]; then echo "Error executing \"$1\""; fi
90 # Returns the number of routing rules in routing table $table
91 function get_num_rules(){
94 ip route show table $table | wc -l
99 # Assign a routing table to the sliver (by creating a mapping in
100 # /etc/iproute2/rt_tables).
101 # If all the routing tables are assigned, remove the mappings
102 # for slivers that do not have rules in their routing
104 function create_table(){
106 local table_sliver=$1
108 #if the table already exists, returns immediately
109 if grep "$table_sliver" $RT_TABLES >/dev/null 2>&1; then
113 #... otherwise find a free routing table to assign to the sliver
115 while [[ $k -lt $((LAST_TABLE+1)) ]] && grep "$k " $RT_TABLES >/dev/null 2>&1 ; do
119 #if all were already assigned, remove unused assignements
120 if [[ $k == $((LAST_TABLE+1)) ]]; then
122 while [[ $k -lt $((LAST_TABLE+1)) ]] && grep "$k " $RT_TABLES >/dev/null 2>&1 ; do
123 if [[ `get_num_rules $k` == 0 ]]; then
124 delete_table `cat $RT_TABLES | grep "$k " | cut -d " " -f 2`
129 #pick the first that has become available, if any
131 while [[ $k -lt $((LAST_TABLE+1)) ]] && grep "$k " $RT_TABLES >/dev/null 2>&1 ; do
135 #otherwise give up and return that no table is available
136 if [[ $k == $((LAST_TABLE+1)) ]]; then
137 echo "No routing tables available. Exiting."
143 echo "$k $table_sliver" >> $RT_TABLES
145 set_routes $sliver $table_sliver
150 # Delete the slice-specific routing table
151 function delete_table(){
153 local sliver=`basename $table_name "_slcip"`
155 if ! grep $table_name $RT_TABLES > /dev/null 2>&1; then
158 exec "ip route flush table $table_name" >/dev/null 2>&1
159 unset_routes $sliver $table_name
160 remove_line "$RT_TABLES" "$table_name"
166 # Remove a line from a file
167 function remove_line(){
171 #remove interface line from the file
172 exec "sed -i /${regex}/d $filename"
175 # Get the slice-specific routing table name
176 function get_table_name(){
178 echo "${sliver}_slcip"
181 # Remove files used by sliceip and the added routing tables
182 function clean_iproute_conf(){
183 while grep "slcip" $RT_TABLES >/dev/null 2>&1; do
184 remove_line $RT_TABLES "slcip"
189 # Get sliver's virtual interface
190 function get_sliver_veth(){
192 cat /var/run/libvirt/lxc/$sliver.xml | grep "target dev" | cut -d "=" -f 2 | cut -d "'" -f 2
195 function get_sliver_ip(){
200 ip=`echo "ifconfig $interface" | lxcsu $sliver | grep inet\ addr | cut -d ":" -f 2 | cut -d " " -f 1`;
202 if valid_dotted_quad $ip; then
212 # set the firewall rules.
213 # Basically source routing is enabled.
214 function set_routes(){
217 #local sliver_veth=`get_sliver_veth $sliver`
218 local sliver_ip=`get_sliver_ip $sliver`
220 # Set $table_name as routing table for the sliver
221 # through source routing
222 #exec "ip rule add iif $sliver_veth table $table_name"
223 exec "ip rule add from $sliver_ip table $table_name"
225 exec "ip route flush cache" >/dev/null 2>&1
227 #Flush stale routing rules in $table_name
228 exec "ip route flush table $table_name"
232 # Remove the firewall rules.
233 function unset_routes(){
236 #local sliver_veth=`get_sliver_veth $sliver`
237 local sliver_ip=`get_sliver_ip $sliver`
240 # Unset $table_name as routing table for the sliver
241 # through source routing
242 exec "ip rule del from $sliver_ip table $table_name"
244 exec "ip route flush cache" >/dev/null 2>&1
248 # Get the ip address of an interface
249 function get_address(){
253 ip=`ifconfig $interface | grep inet\ addr | cut -d ":" -f 2 | cut -d " " -f 1`;
255 if valid_dotted_quad $ip; then
272 # Check an ip address for correcteness
273 function valid_dotted_quad(){
283 ""|*[!0-9]*) return 1; break ;; ## Segment empty or non-numeric char
284 *) [ $seg -gt 255 ] && return 2 ;;
288 return 3 ## Not 4 segments
295 # Check to see if the command start with "route"
296 function checkCommand(){
299 local first=`echo "$cmd" | awk '{print $1}'`
300 #local second=`echo $cmd | awk '{print $2}'`
303 if [[ "$first" != "route" ]]; then
304 echo "Command must start with route."
313 # the script starts here
315 if [[ $sliver == "" ]]; then
316 echo "I need the first argument (the sliver name)";
320 # read a line from the vsys pipe
323 # separate the first two words of the line from the rest
324 command=`echo $line | awk '{print $1 " " $2}'`
325 rest=`echo $line | awk '{ for (i = 3; i<=NF; i++) { printf "%s ",$i } }'`
327 #rest=`echo ${line#* }`
333 #enable and disable kept for compatibility
334 logger "sliceip command received from $sliver: $line"
338 logger "sliceip command received from $sliver: $line"
342 logger "sliceip command received from $sliver: $line"
344 #no concurrent executions of sliceip allowed
345 while ! mkdir /tmp/sliceip.lock >/dev/null 2>&1; do
349 table_sliver=`get_table_name $sliver`
351 #checks the command, creates the routing table and adds the rule
352 if checkCommand "$command" && create_table $table_sliver; then
355 #add the routing rule - ip is called with the same parameters of sliceip but the indication of
356 #the table in which the rule is to be inserted is inserted
357 exec "ip $command table $table_sliver $rest"
362 rmdir /tmp/sliceip.lock