Please meet with your group members and get started on the lab as soon as possible. In general, in this class you will have about 2 weeks from the lab release date until the due date.
I have created a Git repository for each group. You should have already received an invite to access your repository on LoboGit. If you did not receive such an invite, contact me immediately.
The name of your repository will be teamXX
, where XX
are digits. You should be able to view the repository
online at https://lobogit.unm.edu/net-f18/lab4/teamXX.
You will use the git tool on Linux to access the repository.
Cloning the Repository via HTTPS (Easy)
This is the easiest method of accessing your repository. Git will prompt you for your UNM NetID/password.
cd ~
mkdir -p net-f18
cd net-f18
git clone https://lobogit.unm.edu/net-f18/lab4/teamXX.git lab4
cd lab4
Here, you should be able to type ls
(list files) and see the skeleton structure which your lab 3 submission
should follow.
Cloning the Repository via SSH (More Difficult)
If you don't wish to type your NetID/password, you can instead use public-key authentication. First (if you haven't already done so), you need to create a key pair for public-key authentication (git will use this instead of username/password for authentication).
mkdir -p ~/.ssh
chmod 700 ~/.ssh
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "YOUR_ADDRESS@unm.edu" -f id_rsa
(where YOUR_ADDRESS@unm.edu is your UNM email address). This creates a public key (id_rsa.pub) and a private key (id_rsa). KEEP YOUR PRIVATE KEY SECURE AT ALL TIMES! Open the public key (id_rsa.pub) in a text editor
pluma ~/.ssh/id_rsa.pub
and copy the contents into the "SSH Keys" section of your "Settings" on LoboGit. Once the public key is added on LoboGit, you can do
cd ~
mkdir -p net-f18
cd net-f18
git clone git@lobogit.unm.edu:net-f18/lab4/teamXX.git lab4
cd lab4
Here, you should be able to type "ls" (list files) and see the skeleton structure which your lab 2 submission should follow.
For this lab, you will be given a virtual machine (VM) with sudo permissions, i.e., you will have administrative privileges (unlike on the CS lab machines). This will give you greater freedom in experimenting with the machine's protocol stack.
BE CAREFUL when using sudo on your machine! With great power comes great responsibility!
Your VM can only be reached via one of our classroom machines. If you are not in the classroom, you can access the machines remotely:
ssh -X username@b146-xx.cs.unm.edu
(where username is your CS username, and xx is between 01 and 76).
You will need at least two terminals open on the classroom machine, so either open a new terminal, or start a second SSH connection.
In one terminal, type the following commands
cd /b146vpn
openvpn b146fw-udp-1194.ovpn
and enter your CS username/password when prompted. This authenticates you with the virtual private network (VPN) needed to access your VM.
NOTE: if you get an error about the address already being in use, that means the VPN client is already running! In this case, just skip the VPN step and continue with the following instructions.
In the other open terminal, you should be able to log into your VM
ssh -X username@10.200.2.yyy
NOTE: Replace username
with the username you've been sent via email (it
should be the same as your NetID username).
The 10.200.2.yyy
is a unique IP address for your VM, which you will be sent via email.
DO NOT try to log into a VM until you are assigned a username and IP address via email!
Your VM password is initially set PassXXXXXX!
, where XXXXXX
is the unique
six-digit ID you were assigned via email at the beginning of the class.
The first time you log in, you will be asked to change your password.
When asked for "Current UNIX password", repeat the PassXXXXXX!
password,
and then you'll be asked to type a new password twice.
The new password can be anything you want (this VM account is not connected
to your UNM account, or your CS account -- the VM will only be used in this
class).
Once you are logged into your VM, install some utilities:
sudo apt-get install mininet xterm pcapfix python-dpkt python-numpy python-cairo make gnuplot texlive-latex-extra mupdf xpdf evince graphviz iperf3 bridge-utils
sudo sed "s/disable_lua = false/disable_lua = true/g" -i /usr/share/wireshark/init.lua
sudo sed "s/stp_enable=true' %/stp_enable=true' #%/g" -i /usr/lib/python2.7/dist-packages/mininet/node.py
mkdir -p ~/git && cd ~/git
git clone https://github.com/hgn/captcp.git
cd captcp
sudo make install
cd ~
Error detection is an important service provided by the link layer (Layer 2 of the protocol stack), and also appears in higher layers. In this part of the lab, we will look at Ethernet frames (link-layer packets) more closely, and learn how the error detection mechanism(s) works.
In particular, we will use the Python raw sockets interface to send Ethernet frames directly to the link layer on the NIC. This will allow us to customize various parts of a frame, including the cyclic redundancy check (CRC) field at the end.
The checksum
folder in your repository contains skeleton code to help you get started. This code is initally using an included library to do the error detection -
you will need to write your own function(s) to do this. To run the code, do the following:
cd checksum
sudo ../mini.py -c openflow
At the Mininet prompt, type xterm h1 h1
to get two terminals. In one terminal, type
sudo wireshark -k -i h1-eth0
and in the other, type
sudo ./main.py -d 10.0.0.2 -m 10:00:00:00:00:02
This Python script creates an Ethernet frame containing an ICMP (ping) packet and sends it to
the NIC on host h1
, so you should see the ICMP request show up in Wireshark,
followed by an ICMP response from host h2
.
If you click on the ICMP request, and then open the Ethernet II
field below, you can inspect
the CRC by looking at the "Frame check sequence" field. Wireshark will tell you whether the
CRC is valid. Additionally, you can inspect the Internet checksum, i.e., the network-layer
error detection code, by opening the Internet Protocol Version 4
field, and looking
at Header checksum
.
To make Wireshark validate the checksum, select
Edit -> Preferences -> Protocols -> IPv4 -> "Validate the IPv4 checksum if possible" and click
Ok.
If either of these error detection codes is invalid, the ICMP request packet will likely be
dropped before it reaches the destination host, meaning you will not see an ICMP reply from
host h2
in that case.
Task A - Write your own function to compute the CRC32 for the Ethernet frame. You can use the existing function in the code as a "black box" to compare your CRC32 functionality against.
Task B - Write your own function to compute the Internet checksum over the IP header within the Ethernet frame. Again, you can use the existing function to compare your functionality against.
In Part 1, we used the following command to send an Ethernet frame to the NIC on host h1
:
sudo ./main.py -d 10.0.0.2 -m 10:00:00:00:00:02
Notice that we are manually specifying the destination MAC address (link-layer address) of the frame.
In general, we would only know the IP address 10.0.0.2
of the destination, and we would need some
mechanism for determining the destination's MAC address.
This is where the address resolution protocol (ARP) is used - host h1
can send out an ARP
request for address 10.0.0.2
, and when host h2
sees the request, it can respond with its MAC address.
In this part of the lab, instead of manually specifying the MAC address of the destination, we will use ARP to "automatically" determine it.
Task A - Complete the getMAC()
function in checksum/main.py
. You will need to create an ARP
request packet, send it to the NIC, and then receive packets until you see the ARP reply from the
destination. Once you receive this reply, extract the MAC address, and return it.
Task B - If you have completed Task A correctly, your can now run your code as follows:
sudo ./main.py -d 10.0.0.2
Notice that we do not specify the MAC address (it is determined via ARP). More specifically, do the following to make sure your code is fully working:
cd checksum
sudo ../mini.py -c openflow -r
NOTE: the -r
option causes the MAC addresses of thse hosts in Mininet to be randomized,
so you can check that your code is actually getting the correct MAC address.
At the Mininet prompt, type xterm h1 h1
to get two terminals. In one terminal, type
sudo wireshark -k -i h1-eth0
and in the other, type
sudo ./main.py -d 10.0.0.2
You should see the ICMP request and reply show up in Wireshark, and inspecting the ICMP request packet should show the properly-computed destination MAC address.
Recall from the previous lab how we manually installed forwarding rules on the switches in order to set up the routes between the various hosts. In this part of the lab, we will investigate how software-defined networking (SDN) allows us to do this automatically.
In particular, we will build what's called a learning switch - the forwarding rules on the switches will be added on demand, based on the traffic that's being sent to them.
The basic idea of SDN is that all of the switches connect to a special machine called a controller. In our case, the communication between the switches and the controller is out-of-band (these messages do not flow through the network like the ICMP/ARP packets we've seen so far), and uses an API known as OpenFlow (we will use OpenFlow 1.0).
You can see how this works by experimenting with the OpenFlow 1.0 reference controller. First, run the following in one terminal:
controller ptcp:localhost:6633 -v --log-file=mylog
In another terminal, start up Mininet using the custom startup script:
sudo ./mini.py -c remote
Mininet should wait a few seconds as the switches connect to the controller, and then you should see the controller begin to emit a large amount of debugging output, showing you what OpenFlow messages are being received/sent at the controller.
This OpenFlow 1.0 controller implements the learning switch, so while the
controller is running, communication between hosts should be enabled in Mininet.
For example, if you type h1 ping h2
, the controller is able to set up the
route to allow these pings to succeed.
Task A - Look through the code, starting with the run()
function in
SwitchHandler.java
, and make sure you understand the basics of what it is
doing.
The OpenFlow 1.0 Specification
will be very helpful in learning about the different messages, and their
correct order.
Task B - Implement your own learning switch, using the SDN controller
skeleton code provided for you in the controller
directory of your
repository.
The place your code needs to be added is in the handlePacketIn()
method of SwitchHandler.java
.
A very clear description of the learning switch algorithm implemented on a different
SDN controller (known as POX) can be found
here: L2 Learning Switch.
Upon receiving a packet from a switch, you will need to send two types of messages back to
the switch: (1) a PacketOut message, which causes the packet to be flooded on all interfaces except
the one it arrived on (PacketOut functionality is already provided for you),
and (2) a FlowMod message(s) which install rules based on the reverse path of the packet (you will
need to build the FlowMod functionality, and you can see how this is done for PacketOut).
The graphical guide to OpenFlow 1.0 Messages should be very helpful as you think about which PacketOut and FlowMod messages you should send back to the switch.
Clearly document (using source-code comments) all of your work. Also fill in the README.md file (preferably using Markdown syntax) with a brief writeup about the design choices you made in your code.
Providing adequate documentation helps me see that you understand the code you've written.