In this assignment, you will create two switches that implement forwarding within a L2 (link layer) network. First, you will create a static switch which will show how switches forward. This will use a much smaller configuration (you'll see why!). Second, you will create learning switch for a much larger topology wherein switches learn which port to forward traffic to get to any end host. Real L2 switches can and do use either method, though the latter (self-learning) is much more prevalent due to its hands-off management and easier scalability.
This assignment is also a quick introduction to software-defined networking (SDN). Traditional switches have a forwarding plane (which moves packets from port to port on a switch) and a control plane (which decides where packets need to go and tells the forwarding plane how to do this) on the same piece of hardware. SDN changes this: switches become 'dumb' - they are just forwarding planes - while the control plane becomes a program running on a server. In this assignment, the forwarding will take place on virtual switches in Mininet, and the controller will run as a Python program. The code you write will actually run in the controller, which in turn controls the behavior of the Mininet switches. The behaviors you are creating here are pretty basic (compared to SDN's full capabilities), and they are typically implemented in traditional switches in hardware rather than in software, but we are doing it this way so you can get hand-on experience with how switches work.
For this assignment, you will be using the Pyretic controller to program the switches. Much of the difficult parts are abstracted out in the helper file included within the assignment, but there are some features that you will need to read up on. See the wiki and this page in particular to get a feel for the language. We have also posted information on Pyretic in Piazza.
Before getting started, you will need to update your CS6250 repository using the following commands from the OMS6250-2015-Fall directory:
git commit -a -m "Saving work"
git pull --rebase
In the new
assignment-2 directory, there are several files. The files that end with
-topo.py are the topology files that you will use to run the
assignments. You will not have to modify them. The files named
learning-switch.py are the controllers for the static forwarding switch and the learning switch, respectively. These are they only two files you will need to modify and are the two files that you will turn in at the end of the assignment.
helpers.py contains helper functions that we've provided for you to use. You will need to use the print routines in it to output your results in a format that we can grade. You can read up on
__init__.py here and here, but for the most part you'll be able to ignore this file.
output_validator.py is a script you can run on your output files to check that they are in the correct format. It does not check that your data or results are correct, just that the file format is valid. Also, we can't promise that it will catch all file format errors, but it should catch many of the common mistakes. Finally,
run.sh is a shell script to you help start the Pyretic controller and run the controller code that you write.
In theory, you can complete the assignment by only ever looking at
helpers.py. However, please feel free to look at the other files and figure out how they work in as much depth and detail as you care to know! (Looking at the
*-topo.py topology files may be especially helpful.) Also, bear in mind that you will only be turning in
learning-switch.py. While we aren't telling you not to modify any of the other files, bear in mind that if your code depends on changes to any files that we aren't asking you to submit, then your program won't be run with those changes when we go to grade it (we will use the original version of all files except the two you submit).
Static switching is where we manually fill in switch tables (i.e., the forwarding tables), matching the destination MAC address to the port the packets should go out of. (When we say "port" here, we mean the physical interface and not the port number of a socket. This is one of those unfortunately scenarios where one word has two meanings.) It is similar to how static routing works, except at the MAC layer rather than IP layer. There are serious problems, however. First, it doesn't scale well - for each end host, each switch must have a forwarding path programmed in. Second, it cannot handle dynamic changes - if a host moves from Switch A to Switch B, many, possibly all, switches have to have the forwarding path updated. Third, it's highly error prone due to its manual nature.
What it does do is provide us with a good example of how to deal with Pyretic, in particular manipulating packets and creating forwarding behavior. It also shows us how forwarding behavior is implemented by keying off of the destination MAC address to make forwarding decisions.
The topology we are using is above. In code, Switch 1 is Switch A in the diagram above, and Switch 2 is Switch B. This is to simplify descriptions using the diagram, and a limitation of Mininet.
Before you begin, be sure to do a fresh pull from git to make sure you have the latest starter code, as described above!
Look in the file
static-forwarding-topo.py. This is a description of the topology. It's very simple. You can start simulating this network in Mininet by running the command
sudo python static-forwarding-topo.py in a terminal. If you see a warning about
Unable to contact the remote controller, you can ignore that. As long as you get the
mininet> prompt, it's working.
mininet> prompt, you can run commands on hosts/switches by giving the name of the host/switch followed by the command. For example,
h1 ifconfig will run ifconfig on host h1. Any command or program a machine can normally run can be run within Mininet this way. This can be useful for querying the topology for details about the hosts/switches.
Now, you will need to make changes to
static-forwarding.py in the sections marked
TODO. As it stands, this file will not run without your modifications. There is significant example code that you can base your code on.
It will be useful to know that MAC addresses are assigned to the hosts as
00:00:00:00:00:01 to the first host (i.e., the first call to
00:00:00:00:00:02 to the second, and so forth...
You also need to make sure the broadcast MAC
ff:ff:ff:ff:ff:ff is forwarded to all ports. Some starter code for this is provided.
When you have written your forwarding table, you must write out your forwarding configuration. Use the
write_forwarding_entry() function near the beginning of
helpers.py. This is covered in one of the TODOs already, with details on how to log this. This will write out to the file
static-forwarding.log. Note: Please do not post your static-forwarding logs into Piazza, as this can be considered cheating (posting logs for the learning switch is encouraged however).
To run your code, we have provided you with a convenient
run.sh shell script that will copy your controller code over to the pyretic directory, then run it with Pyretic. With the Mininet topology still running in a terminal window (repeat step 1 if it is not still running), open a new terminal window and execute
./run.sh static-forwarding. This starts up the controller and begins running your code, so now you have a Mininet network simulation running in one terminal window and a Pyretic SDN controller running in another terminal window.
At this point, you should be able to run commands at the
mininet> prompt and see that the network is working properly. Specifically, any host should be able to reach any other host, and the switches should not have to flood any packets to do this. (ARP requests will still broadcast, though, because the protocol explicitly states that those are broadcast.) You can use ping to test this, e.g.,
h1 ping h2 and so on to test all combinations for connectivity.
This will produce a
static-forwarding.log output file in your Pyretic directory (
~/pyretic/). You do not need to turn in your log files, but when we execute your code it will generate new log files for us that we will look at. It is very important that the file format of the log files is exactly correct, so our log parsing code can read them correctly. To help with this, we have provided the Python script
output_validator.py to check your log file for errors. It does not check that your data is actually correct for the assignment; it only checks that the format is valid, so it's still up to you to make sure your code works properly. You should run the output validator on your
static-forwarding.log file now.
We're going to go over how learning switches work again, just in case, using the topology from the first part of the assignment.
When the topology has just come up, the switch tables are empty. When a packet goes from Host 1 (with MAC address 1, for simplicity's sake), and is destined for Host 2, it first goes to Switch A. Switch A will record which port Host 1 came in on. Since Switch A does not know where the MAC address for 2 is, will flood and send a copy of the packet to both remaining ports. It will reach Host 2, but it will also reach Switch 2. Switch 2 will save off how to get to Host 1 (via Switch 1), and flood to hosts 3 and 4.
If, afterward, Host 3 is trying to send a packet to Host 1, Switch B learn how to get to Host 3, will not flood and send it directly to Switch A. Switch A will also learn how to get to Host 3 (via Switch B), and forward directly to Host 1.
Above is the topology provided for the assignment. There are significantly more switches than in the review, however this allows for more test cases possible. You will be able to use both this topology and the one for the static part of the assignment for testing purposes.
Completing this part of the assignment is similar to the first half.
Look in the file
learning-switch-topo.py. It's much more complicated than
static-forwarding-topo.py but you can run in the same way. You can (and should!) use both topologies for your own testing. See the hints below about testing.
learning-switch.py there are a number of TODOs that you need to handle. There are two major functions you will need to implement.
learn_route() is where you learn the L2 paths between hosts and switches.
print_switch_tables() logs the switch tables to the log file. We have provided a number of helper functions that can be used (see
helpers.py) both for logging and for pulling out specific field out of network headers (there are extra functions that you won't use but are provided for completeness).
You also need to make sure the broadcast MAC
ff:ff:ff:ff:ff:ff is forwarded to all ports. Refer to the starter code from the static forwarding portion to see how this can be done.
Running your code is similar to before. With the Mininet topology already running in another terminal window, start your Pyretic controller code using the
run.sh script. Once both are started, you can run tests at the
Note that if you test with ping, the first few pings (usually ~3) may not go through while the switch learns and the ARP protocol runs, so allow several pings before you conclude it's not working... However, once a path is learned, subsequent pings should go through okay.
Test your code. We'll grade your learning switch using all the topologies that we provided you, plus several others. So you should test your code against all the topologies we provided you, plus create some of your own and/or get some from your fellow students. (Feel free to share any topologies you create on Piazza!)
Run the output validator script on your
learning-switch.log output file.
You will need to turn in two files:
BE SURE TO USE THE CORRECT FILE NAME OR YOU WILL RECEIVE A ZERO. If our grading scripts can't find your files, then they can't grade them! The correct file names are the ones they have when we give them to you, so in theory you should be fine as long as you simply don't ever rename the files, but it's always best to double check when you're turning them in.
For the static forwarding part, we will use the exact same topology as you did. For the learning switch, we will be using all the provided topologies, plus several different ones so that we can be sure that your code is actually learning. For the learning switch, do not use outside code. There is plenty of it existing - which you can review, but not use. All code that you turn in must be written by your own hand.
Do not share the following files with your fellow students, on Piazza, or publicly.
You may share your
learning-switch.log files for any topology, and you may also share any code you write that will not be turned in, such as new topologies or other testing code. (It may be a good idea to share a "correct"
learning-switch.log for a particular topology, if you have one, when you share the code for that topology.)
Exception: Error creating interface pair: RTNETLINK answers: File exists- when running the topology on subsequent runs (it should never be seen immediately upon boot). This is caused by Mininet not cleaning up the virtual switches and hosts correctly. Fortunately, Mininet can clean up manually by running
sudo mn -cto clear this.
run.shscript is here to help with that.
|2 pts||Correct Submission||for turning in all the correct files with the correct names, and significant effort has been made in each file towards completing the assignment|
|2 pts||Static Forwarding||for correct functioning of static forwarding switches using the provided static forwarding topology|
|6 pts||Learning Switch (6 topologies)||for correct functioning of learning switches on six different topologies of varying complexity (0, 0.5, or 1 pt. could be awarded for each topology)|