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