The Plan
OpenFlow is a simple concept - an open interface to switch and router hardware. Can we tie this into an open web framework to create a foundation for a really simple Web UI?
The tools
I've been learning how to use Django recently, and it seems like a perfect choice for this task. It's written in Python, so it integrates easily with the POX controller. I've also used virtualenv to make it more portable - this means the project is largely self-contained and can be copied to a new system by simply copying the folder.
Implementation
To start, I created a virtualenv called "djangoflow" on an Ubuntu machine and installed django in it. There are lots of ways to do this - do a google for "django setup virtualenv ubuntu" and you'll get tons of hits.
I made a project called mysite, and an app called flew (NZ english for "flow"), and left that bit for the time being.
The folder structure then looks something like this:
djangoflow
- bin
- include
- lib
- local
- mysite
--- flew
--- mysite
I then did a git clone of the latest build of POX from the NOXREPO github, into the djangoflow folder, and then copied everything from the base mysite folder into the pox folder. The folder structure then looks like:
djangoflow
- bin
- include
- lib
- local
- pox
--- .git
--- flew
--- mysite
--- pox
This is great - now back to Django.
The model that I used was really simple, here's what I've got so far:
from django.db import models
# Create your models here.
class Flow(models.Model):
internalip = models.CharField(max_length=200)
externalip = models.CharField(max_length=200)
idletime = models.IntegerField()
hardtime = models.IntegerField()
def __unicode__(self):
return "Internal: " + self.internalip + ", External: " + self.externalip
class User(models.Model):
name = models.CharField(max_length=200)
class Device(models.Model):
dpid = models.CharField(max_length=200)
We'll only use the Flow model today, the others are for expansion later. To make this work, we'll need to edit the settings in mysite.settings - set up the databases and installed_apps sections as follows:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'flew.db', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
# 'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
'django.contrib.admindocs',
'flew',
)
Awesome, now run syncdb (check against whatever tutorial you use to see how this is done) and populate the database. Now, fire up the shell and create your first flow:
python manage.py shell
from flew.models import Flow
f = Flow(internalip = "10.1.10.2", externalip = "10.1.20.2", idletime = 300, hardtime = 3600)
f.save()
If that all worked, then you'll have a new entry in your database. We are never going to access the database directly though - we can access all the Django goodness from POX.
Open up pox/forwarding/l2_learning.py and have a look through - if you've used this before, then good, if not, then see what it all does.
I've hijacked this just for this example, but it sets a starting point for any POX-Django integrated tools. Make sure your imports section looks like this:
# import django stuff
from django.core.management import setup_environ
from mysite import settings
setup_environ(settings)
from flew.models import Flow
from pox.core import core
import pox.openflow.libopenflow_01 as of
from pox.lib.revent import *
from pox.lib.util import dpidToStr
from pox.lib.util import str_to_bool
from pox.lib.packet import ethernet
from pox.lib.packet import ipv4
import time
Then go down to the __init__ function for LearningSwitch and add this to the end:
# add new flow by default
flow1 = Flow.objects.all()[0]
msg = of.ofp_flow_mod()
msg.match = of.ofp_match()
msg.match.dl_type = ethernet.IP_TYPE
msg.match.nw_src = str(flow1.internalip)
msg.match.nw_dst = str(flow1.externalip)
msg.idle_timeout = flow1.idletime
msg.hard_timeout = flow1.hardtime
msg.actions.append(of.ofp_action_output(port = 1))
#msg.buffer_id = event.ofp.buffer_id # 6a
self.connection.send(msg)
What does this do? It takes the first Flow out of our database, creates a flow to allow traffic from internalip, going to externalip, to go out port 1, which should be pointing at the outside world. This flow will stay in the switch for an hour, or 5 minutes without being triggered - whichever happens first.
Question time
Q: Is it really this easy?
A: Yes. Python is easy, Django is easy, Virtualenv is easy, POX is easy. It's just a little tricky making them all work together - that's what this guide is for.
Q: Why add flows this way when we already have a CLI?
A: Django has a clean admin interface that I haven't covered here (check the setup tutorial on the Django website) - you can set flows in there, and every time a switch connects, it will use those flows.
Q: Could I start using this right now?
A: Totally. If you want your switches to retrieve their configuration from the controller automatically when they start up, you can set a bunch of super specific flows here and roll it out now. If you want something a bit more clever, then you can jump into the Django and POX API and make it happen yourself.
Q: What next?
A: There are two extra models that we didn't use - one for user authentication, and one for managing devices. If your OpenFlow devices connect by SSL (which they should in the real world) then you can create models for them that hold particular flows - this can all be managed via a web interface. As for user authentication, there are millions of ways to do this - you can set privileges for who can set certain flows, make requests that admins can approve - the possibilities are endless!