Summary

OpenFlow is a technology for implementing software defined networking (SDN). This Document guides you through a hands-on example on how to create a learning switch with Trema a full stack SDN development environment.

To demonstrate OpenFlow and its usage we use a switch that “learns” the hosts on its network. The network consists of one switch and two hosts:

Learning Switch

Trema uses a build in OpenVswitch for the switching. This can be seen in the process list:

vagrant@vagrant:~$ ps -ef|grep switch
vagrant  18248  2891  0 01:05 pts/2    00:00:00 /usr/bin/ruby1.8 /usr/local/bin/trema run learning_switch.rb -c learning-switch.conf
vagrant  18254     1  0 01:05 ?        00:00:00 /var/lib/gems/1.8/gems/trema-0.2.5/objects/switch_manager/switch_manager --daemonize --port=6633 -- port_status::LearningSwitch packet_in::LearningSwitch state_notify::LearningSwitch vendor::LearningSwitch
root     18325     1  0 01:05 ?        00:00:08 /var/lib/gems/1.8/gems/trema-0.2.5/objects/openvswitch/bin/ovs-openflowd --detach --out-of-band --fail=closed --inactivity-probe=180 --rate-limit=40000 --burst-limit=20000 --pidfile=/var/lib/gems/1.8/gems/trema-0.2.5/tmp/pid/open_vswitch.0xabc.pid --verbose=ANY:file:dbg --verbose=ANY:console:err --log-file=/var/lib/gems/1.8/gems/trema-0.2.5/tmp/log/openflowd.0xabc.log --datapath-id=0000000000000abc --unixctl=/var/lib/gems/1.8/gems/trema-0.2.5/tmp/sock/ovs-openflowd.0xabc.ctl --ports=trema0-0,trema1-0 netdev@vsw_0xabc tcp:127.0.0.1:6633
vagrant  18329     1  0 01:05 ?        00:00:00 switch.127.0.0.1:49381 --name=switch.127.0.0.1:49381 --socket=3 --daemonize state_notify::switch_manager port_status::LearningSwitch packet_in::LearningSwitch state_notify::LearningSwitch vendor::LearningSwitch

The Network Configuration

The Trema network configuration for this switch is:

vswitch { dpid "0xabc" }

vhost ("host1") {
  ip "192.168.0.1"
  netmask "255.255.0.0"
  mac "00:00:00:01:00:01"
}

vhost ("host2") {
  ip "192.168.0.2"
  netmask "255.255.0.0"
  mac "00:00:00:01:00:02"
}

link "0xabc", "host1"
link "0xabc", "host2"

The Learning Switch Application

The purpose of the learning switch is to memorize which host is connected to which port of the switch and send packages to the known hosts.

Lookup Table

So first we need something to store and retrieve this kind of information in the controller. What we want to do is have a mac address and get a port id or put a port id to a mac adress. This is simply a Hash:

class FDB
  def initialize
    @db = {}
  end

  def lookup mac
    @db[ mac ]
  end

  def learn mac, port_no
    @db[ mac ] = port_no
  end
end 

Another thing to take away from this is that the controller knows about the configuration. We simply could store this somewhere remote in a service application and connect to it later on (e.g. to initialize a switch)

Lookup Or Learn

If we receive a message we learn the mac address of the host connected to the port and lookup the destination of the message. If we already have seen a message from the source mac address we get a port_no from the lookup and will send the message to this port. If not we simply flood the message.

class LearningSwitch < Controller

...

  def packet_in dpid, message
    @fdb.learn message.macsa, message.in_port
    port_no = @fdb.lookup( message.macda )
    if port_no
      flow_mod dpid, message, port_no
      packet_out dpid, message, port_no
    else
      flood dpid, message
    end
  end

...

end

So how does the switch know what to do with a message? We have to update the flow table of the switch. This is done with the flow_mod method.

  def flow_mod dpid, message, port_no
    send_flow_mod_add(
      dpid,
      :match => ExactMatch.from( message ),
      :actions => ActionOutput.new( port_no )
    )
  end

Simply put this means: If you ever see a message like this one send it the port port_no. This does update the flow table to actually send the message during this flow-table update process we additionally have to send it. This is done with the packet_out method:

  def packet_out dpid, message, port_no
    send_packet_out(
      dpid,
      :packet_in => message,
      :actions => ActionOutput.new( port_no )
    )
  end

The only thing missing is what to do with a message we do not have neither a flow table entry nor a controller lookup result? We flood it to all ports with the flood method:

  def flood dpid, message
    packet_out dpid, message, OFPP_FLOOD
  end

Learning Switch Demonstration

There is a vagrant Virtualbox with Trema already installed and the learning switch example ready to use at: https://github.com/ehaselwanter/virtualbox-sdn

Terminal 1:

trema run learning_switch.rb -c learning-switch.conf 

Terminal 2:

vagrant@vagrant:~$ trema dump_flows 0xabc
NXST_FLOW reply (xid=0x4):

vagrant@vagrant:~$ trema show_stats host2
Sent packets:

Received packets:

vagrant@vagrant:~$  watch trema show_stats host2

Terminal 3:

trema send_packet --source host1 --dest host2
trema send_packet --source host1 --dest host2
trema send_packet --source host2 --dest host1
trema send_packet --source host2 --dest host1

vagrant@vagrant:~$ trema show_stats host2
Sent packets:
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.0.1,1,192.168.0.2,1,2,100
Received packets:
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.0.2,1,192.168.0.1,1,2,100
vagrant@vagrant:~$ trema show_stats host1
Sent packets:
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.0.2,1,192.168.0.1,1,2,100
Received packets:
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.0.1,1,192.168.0.2,1,2,100

vagrant@vagrant:~$ trema dump_flows 0xabc
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=180.465s, table=0, n_packets=1, n_bytes=64, priority=65535,udp,in_port=1,vlan_tci=0x0000,dl_src=00:00:00:01:00:02,dl_dst=00:00:00:01:00:01,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,tp_src=1,tp_dst=1 actions=output:2

trema send_packet --source host1 --dest host2
trema send_packet --source host1 --dest host2
trema send_packet --source host2 --dest host1
trema send_packet --source host2 --dest host1

 vagrant@vagrant:~$ trema dump_flows 0xabc
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=310.596s, table=0, n_packets=3, n_bytes=192, priority=65535,udp,in_port=1,vlan_tci=0x0000,dl_src=00:00:00:01:00:02,dl_dst=00:00:00:01:00:01,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,tp_src=1,tp_dst=1 actions=output:2
 cookie=0x2, duration=54.63s, table=0, n_packets=1, n_bytes=64, priority=65535,udp,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:01:00:01,dl_dst=00:00:00:01:00:02,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,tp_src=1,tp_dst=1 actions=output:1

Interested in Cloud or Chef Trainings? Have a look at our Commandemy Trainings page. Need help migrating to the cloud? Check out Infralovers.

comments powered by Disqus
Blog Tags