Part 1 Preparation before script can be written
Step 1 Create multiple read-only UML instances
To start multiple instances in read-only mode is simple. Just remove the w option will be enough.
sudo linux.uml rootfstype=hostfs rootflags=/home/vic/uml/ r umlid=umla eth0=daemon,,unix,/home/vicuml/switch/sw1.ctl sudo linux.uml rootfstype=hostfs rootflags=/home/vic/uml/ r umlid=umlb eth0=daemon,,unix,/home/vicuml/switch/sw1.ctl
The only issue is that the whole file system of the instance became read-only.
Step 2 Create ramfs on the UML instances
In order to let the read-only UML instances run nicely and can keep the logs we need later for investigate the behavior of the protocols, we can create a ramfs to contain these files.
In the /etc/fstab , we will define the /var as ramfs and give it a 25MB limit
none /var ramfs defaults,size=25M 0 0
Next is to mount it in /etc/init.d/rcS and make the folders
mount none /var -t hostfs -o /home/vic/umlvar mkdir /var/lock /var/run /var/log /var/tmp
Step 3 Create virtual console for X use in UML instance
By add the next line into /etc/inittab we have a new terminal connection and can use ssh to connect to the UML instances.
::respawn:/bin/getty -L ttyS0 38400 vt100
Step 4 Use screen command to start multiple UML instances
Screen is a kind of “task manager” it can be used to start multiple command and monitor them. I can resume to any of the command former started by the screen.
## This command will show all the currently monitored program of current user. ## It it notable that if you start with sudo screen, it will show the process of root user instead of current user. screen -ls ## This will let the linux.uml, eventually any command run in background screen -dmS $hostname linux.uml rootfstype=hostfs
Part 2 Write script
Step 1 script on host
#!/bin/sh n=$1 echo "going to create $n networks" screen -dmS sw1 uml_switch -unix /home/vic/uml/switch/sw1.ctl for i in `seq 1 $n` do screen -d -m -S uml$i linux.uml rootfstype=hostfs rootflags=/home/vic/uml/ r umlid=uml$i hostname=uml$i eth0=daemon,,unix,/home/vic/uml/switc/sw1.ctl ip_eth0="10.0.0.$i" mask_eth0="255.255.255.0" bc_eth0="10.1.0.0" done
The host code will need a int parameter. It indicates the amount of instances we are going to startup. The the switch will be brought on first. Then the machines will be brought on afterwards and being assigned the IP addresses.
Step 2 script on UML instances
I add the script into /etc/init.d/rcS
#!/bin/sh mount -a mkdir /var/lock /var/run /var/log /var/tmp hostname $hostname ifconfig lo up if [ -z $role ] then role="host" fi case $role in router) echo "router";; sniffer) echo "sniffer" ip link set eth0 up tcpdump -i eth0 -U -s 0 -w /var/log/$hostname-`date +%H%M`.dmp & echo "INFO: sniffer $hostname activated" ;; bridge) echo "bridge";; host) echo "host: $hostname" if [ ! -z $ip_eth0 ] && [ ! -z $mask_eth0 ] && [ ! -z $bc_eth0 ] then ifconfig eth0 $ip_eth0 netmask $mask_eth0 broadcast $bc_eth0 up fi if [ ! -z $ip_eth1 ] && [ ! -z $mask_eth1 ] && [ ! -z $bc_eth1 ] then ifconfig eth1 up ifconfig eth1 $ip_eth1 netmask $mask_eth1 broadcast $bc_eth1 fi if [ ! -z $ip_eth2 ] && [ ! -z $mask_eth2 ] && [ ! -z $bc_eth2 ] then ifconfig eth2 up ifconfig eth2 $ip_eth2 netmask $mask_eth2 broadcast $bc_eth2 then ifconfig eth2 up ifconfig eth2 $ip_eth2 netmask $mask_eth2 broadcast $bc_eth2 fi if [ ! -z $ip_eth3 ] && [ ! -z $mask_eth3 ] && [ ! -z $bc_eth3 ] then ifconfig eth3 up ifconfig eth3 $ip_eth3 netmask $mask_eth3 broadcast $bc_eth3 fi ;; esac
Step 3 Re-create the simple network
Now I can re-create the simple network in the first assiginment by simply running the next command
vic@vicubuntu:~$ sudo ./network1 2 going to create 2 networks
And I can view the currently started tasks by using screen
vic@vicubuntu:~$ sudo screen -ls There are screens on: 11197.uml2 (02/07/2011 02:39:29 PM) (Detached) 11195.uml1 (02/07/2011 02:39:29 PM) (Detached) 2 Sockets in /var/run/screen/S-root.
I can resume to them by
sudo screen -r uml2
The reason why sudo is there is that, in order to give the UML instances enough privilege to connect to the switch daemon which was started with root privilege, we have to start the UML instances with also root privilege. Hence the UML instances stay in the root space of screen. So, everything is working. Next step is to improve the code.
Extra step Improve the scripts
Now we need for each network a different host script which is in a sense not very “automated”. The plan is to make a script which will read configuration files and create networks according to the contents of it.
The revised host script
#!/bin/sh #netstart [start|stop|stopall] [sniffer|router|switch|hub|host|bridge] [name] #[ip/cidr] [switchname|gw's ip/cidr] action=$1 role=$2 hostname=$3 home="/home/vic/uml" switchhome="/home/vic/umlswitch" case ${action} in start) case ${role} in sniffer) sw=$4 screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname role=$role eth0=daemon,,unix,$switchhome/$sw.ctl echo "sniffer: $hostname conneted to switch: $sw" ;; router) sw1=$4 ip1=$5 mask1=$6 br1=$7 pro=$8 ver=$9 if [ -z "$10" ]; then echo "screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 pro=$pro ver=$ver role=$role" screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 pro=$pro ver=$ver role=$role else sw2=$8 ip2=$9 mask2=$10 br2=$11 pro=$12 ver=$13 if [ -z "$14" ]; then screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ rw umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 eth1=daemon,,unix,$switchhome/$sw2.ctl ip_eth1=$ip2 mask_eth1=$mask2 bc_eth1=$br2 pro=$pro ver=$ver role=$role else sw3=$12 ip3=$13 mask3=$14 br3=$15 pro=$16 ver=$17 if [ -z "$18" ]; then screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 eth1=daemon,,unix,$switchhome/$sw2.ctl ip_eth1=$ip2 mask_eth1=$mask2 bc_eth1=$br2 eth2=daemon,,unix,$switchhome/$sw3.ctl ip_eth2=$ip3 mask_eth2=$mask3 bc_eth2=$br3 pro=$pro ver=$ver role=$role else sw4=$16 ip4=$17 mask4=$18 br4=$19 pro=$20 ver=$21 screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 eth1=daemon,,unix,$switchhome/$sw2.ctl ip_eth1=$ip2 mask_eth1=$mask2 bc_eth1=$br2 eth2=daemon,,unix,$switchhome/$sw3.ctl ip_eth2=$ip3 mask_eth2=$mask3 bc_eth2=$br3 eth3=daemon,,unix,$switchhome/$sw4.ctl ip_eth3=$ip4 mask_eth3=$mask4 bc_eth3=$br4 pro=$pro ver=$ver role=$role fi fi fi #echo $pro #echo $ver if [ $pro = "rip" ] && [ $ver = "1" ]; then cp -P ~/uml/etc/quagga/ripd1.conf ~/uml/etc/quagga/ripd.conf #chown quagga:quagga ~/uml/etc/quagga/ripd.conf #chmod 640 ~/uml/etc/quagga/ripd.conf fi if [ $pro = "rip" ] && [ $ver = "2" ]; then cp ~/uml/etc/quagga/ripd2.conf ~/uml/etc/quagga/ripd.conf #chown -R quagga:quagga /etc/quagga/ripd.conf #chmod 640 /etc/quagga/ripd.conf fi echo "router $hostname started" ;; switch) screen -d -m -S $hostname uml_switch -unix $switchhome/$hostname.ctl & echo "$switchhome/$hostname.ctl" echo "switch $hostname started" ;; hub) screen -d -m -S $hostname uml_switch -hub -unix $switchhome/$hostname.ctl & echo "hub $hostname started" ;; host) sw1=$4 ip1=$5 mask1=$6 br1=$7 gw=$8 if [ -z "$9" ]; then screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 gw=$gw else sw2=$8 ip2=$9 mask2=$10 br2=$11 gw=$12 if [ -z "$13" ]; then screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 eth1=daemon,,unix,$switchhome/$sw2.ctl ip_eth1=$ip2 mask_eth1=$mask2 bc_eth1=$br2 gw=$gw else sw3=$12 ip3=$13 mask3=$14 br3=$15 gw=$16 if [ -z "$17" ]; then screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 eth1=daemon,,unix,$switchhome/$sw2.ctl ip_eth1=$ip2 mask_eth1=$mask2 bc_eth1=$br2 eth2=daemon,,unix,$switchhome/$sw3.ctl ip_eth2=$ip3 mask_eth2=$mask3 bc_eth2=$br3 gw=$gw else sw4=$16 ip4=$17 mask4=$18 br4=$19 gw=$20 screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname eth0=daemon,,unix,$switchhome/$sw1.ctl ip_eth0=$ip1 mask_eth0=$mask1 bc_eth0=$br1 eth1=daemon,,unix,$switchhome/$sw2.ctl ip_eth1=$ip2 mask_eth1=$mask2 bc_eth1=$br2 eth2=daemon,,unix,$switchhome/$sw3.ctl ip_eth2=$ip3 mask_eth2=$mask3 bc_eth2=$br3 eth3=daemon,,unix,$switchhome/$sw4.ctl ip_eth3=$ip4 mask_eth3=$mask4 bc_eth3=$br4 gw=$gw fi fi fi echo "host $hostname started" ;; bridge) macbr=$4 macif1=$5 sw1=$6 #hostname=$macbr if [ -z "$7" ]; then #echo "screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname role=$role hostname=$hostname eth0=daemon,,unix,$home/switch/$sw1.ctl macbr=$macbr macif1=$macif1 sw1=$sw1" screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname role=$role eth0=daemon,,unix,$switchhome/$sw1.ctl macbr=$macbr macif1=$macif1 sw1=$sw1 else macif2=$7 sw2=$8 if [ -z "$9" ]; then #echo "screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname role=$role eth0=daemon,,unix,$home/switch/$sw1 eth1=daemon,,unix,$home/switch/$sw2 macbr=$macbr macif1=$macif1 sw1=$sw1 macif2=$macif2 sw2=$sw2" screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname role=$role eth0=daemon,,unix,$switchhome/$sw1.ctl eth1=daemon,,unix,$switchhome/$sw2.ctl macbr=$macbr macif1=$macif1 sw1=$sw1 macif2=$macif2 sw2=$sw2 else macif3=$9 sw3=$10 #echo "screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname role=$role eth0=daemon,,unix,$switchhome/$sw1.ctl eth1=daemon,,unix,$switchhome/$sw2.ctl eth2=daemon,,unix,$switchhome/$sw3.ctl macbr=$macbr macif1=$macif1 sw1=$sw1 macif2=$macif2 sw2=$sw2 macif3=$macif3 sw3=$sw3" screen -d -m -S $hostname linux.uml rootfstype=hostfs rootflags=$home/ r umlid=$hostname hostname=$hostname role=$role eth0=daemon,,unix,$switchhome/$sw1.ctl eth1=daemon,,unix,$switchhome/$sw2.ctl eth2=daemon,,unix,$switchhome/$sw3.ctl macbr=$macbr macif1=$macif1 sw1=$sw1 macif2=$macif2 sw2=$sw2 macif3=$macif3 sw3=$sw3 fi fi echo "bridge $hostname started" ;; esac ;; stop) echo "stopping all the UML instances" ;; stopall) echo "stopping all the instances and switches" killall linux.uml killall uml_switch echo "everything killed" ;; *) echo "command usage is " echo "netstart [start|stop|stopall] [sniffer|router|switch|hub|host|bridge] [name]" ;; esac
Now the host script will accept parameters and run accordingly to the parameter it was given. and start stop function are also added.
the revised rcS script
#!/bin/sh mount -a mkdir -p /var/run /var/lock /var/log /var/tmp /var/run/quagga chmod 777 /var/* /var/run/quagga mount none /logfile -t hostfs -o /home/vic/umlvar hostname $hostname ifconfig lo up if [ -z $role ] then role="host" fi case $role in router) echo "router $hostname" if [ ! -z $ip_eth0 ] && [ ! -z $mask_eth0 ] && [ ! -z $bc_eth0 ]; then ifconfig eth0 $ip_eth0 netmask $mask_eth0 broadcast $bc_eth0 up fi if [ ! -z $ip_eth1 ] && [ ! -z $mask_eth1 ] && [ ! -z $bc_eth1 ]; then ifconfig eth1 $ip_eth1 netmask $mask_eth1 broadcast $bc_eth1 up fi if [ ! -z $ip_eth2 ] && [ ! -z $mask_eth2 ] && [ ! -z $bc_eth2 ]; then ifconfig eth2 $ip_eth2 netmask $mask_eth2 broadcast $bc_eth2 up fi if [ ! -z $ip_eth3 ] && [ ! -z $mask_eth3 ] && [ ! -z $bc_eth3 ]; then ifconfig eth3 $ip_eth3 netmask $mask_eth3 broadcast $bc_eth3 up fi echo "1" > /proc/sys/net/ipv4/ip_forward /etc/init.d/quagga start echo "INFO: $pro $ver started" ;; sniffer) echo "sniffer" #ip link set eth0 up ifconfig eth0 -arp up tcpdump -i eth0 -U -s 0 -w /logfile/$hostname-`date +%H%M`.dmp & echo "INFO: sniffer $hostname activated" ;; bridge) echo "bridge: $hostname" mount -t hostfs none /lib/modules/ -o /usr/lib/uml/modules modprobe llc modprobe stp modprobe bridge #add br and interfaces /bin/brctl addbr $hostname ifconfig $hostname hw ether $macbr if [ ! -z $macif1 ]; then ifconfig eth0 hw ether $macif1 up /bin/brctl addif $hostname eth0 fi if [ ! -z $macif2 ]; then ifconfig eth1 hw ether $macif2 up /bin/brctl addif $hostname eth1 fi if [ ! -z $macif3 ]; then ifconfig eth2 hw ether $macif3 up /bin/brctl addif $hostname eth2 fi /bin/brctl stp $hostname on ifconfig $hostname up echo "INFO: bridge $hostname activated" ;; host) echo "host: $hostname" if [ ! -z $ip_eth0 ] && [ ! -z $mask_eth0 ] && [ ! -z $bc_eth0 ]; then ifconfig eth0 $ip_eth0 netmask $mask_eth0 broadcast $bc_eth0 up fi if [ ! -z $ip_eth1 ] && [ ! -z $mask_eth1 ] && [ ! -z $bc_eth1 ]; then ifconfig eth1 $ip_eth1 netmask $mask_eth1 broadcast $bc_eth1 up fi if [ ! -z $ip_eth2 ] && [ ! -z $mask_eth2 ] && [ ! -z $bc_eth2 ]; then ifconfig eth2 $ip_eth2 netmask $mask_eth2 broadcast $bc_eth2 up fi if [ ! -z $ip_eth3 ] && [ ! -z $mask_eth3 ] && [ ! -z $bc_eth3 ]; then ifconfig eth3 $ip_eth3 netmask $mask_eth3 broadcast $bc_eth3 up fi if [ ! -z $gw ]; then ip route add default via $gw fi echo "INFO: host $hostname activated" ;; esac
configuration file
#usage: ./netstart [start|stop|stopall|*] [role] [hostname] [switch] [(ip & netmask & broadcast) | br_mac & (port_mac & switch)] [gateway] #start a hub and give it a name (ie. sw1) ./netstart start hub sw1 #start sniffers and give hostname (sniffer1) and then the process file name (sw1) ./netstart start sniffer sniffer1 sw1 #start a host, give host name, switch to connect to, interface to that switch, then optionally a gateway ./netstart start host host1 sw1 192.168.0.1 255.255.255.0 192.168.0.255 192.168.0.100 #start bridges, give hostname, bridge ID, port ID and switch to which the port is connected ./netstart start bridge br1 aa:bb:cc:dd:01:aa aa:bb:cc:dd:01:01 sw1 aa:bb:cc:dd:01:02 sw2 #start a router, give hostname, switch and to which the interface is connected, then routing protocol. optionally protocol version number ./netstart start router routera swa 20.0.0.1 255.0.0.0 20.255.255.255 coreab 10.0.0.1 255.0.0.0 10.255.255.255 coreac 192.168.1.17 255.255.255.240 192.168.1.31 rip 1