Soheil Hassas Yeganeh

Handout #6:

OpenFlow Tutorial

bit.ly/oftutorial

Based on:

OpenFlow.org's OpenFlow Tutorial

Preface

Run anything with dark background in Terminal.

    def there_is_something_like_this():
      return True

    if there_is_something_like_this():
      print('It is a code. Paste it to the respective file.')
  

Before you start

  1. Download one of the images:

    Ubuntu 11.10 (Stable)

    Ubuntu 12.04 (Experimental)

  2. Start the VM.

    You can use either VirtualBox, VMWare, KDM, or Qemu.

    Username: openflow, Password: openflow

Mininet

Mininet is a tool that emulates an arbitrary openflow network on your machine.

How to run mininet:

  1. Open a new terminal (try ssh'ing to your VM).
  2. Run: sudo mn

    Note: The default topology is a line with two hosts (h2 and h3) and a switch (s1).

  3. You should see the mininet terminal: mininet>
  4. Now, ping h3 from h2: mininet> h2 ping h3

Mininet - Specifying a controller

By default, mininet boots its default controller and connects to the controller at localhost:6633.

To specify the controller's address, run:

sudo mn --controller remote --ip 127.0.0.1 --port 6633

Now, ping h3 from h2: mininet> h2 ping h3

Why do the pings fail?

Mininet - Specifying a controller

By default, mininet boots its default controller and connects to the controller at localhost:6633.

To specify the controller's address, run:

sudo mn --controller remote --ip 127.0.0.1 --port 6633

Now, ping h3 from h2: mininet> h2 ping h3

Why do the pings fail?

Because there is no flow entry in s1, packets are forwarded to the controller.

But, you don't have any controller running on your machine.

So, packets are simply dropped!

OpenFlow Controllers

There are a handful of controllers available:

In this tutorial, we use NOX Classic.

Bootstrapping NOX Classic

Open a new terminal.

Run: cd ~/noxcore/build/src/

Then, run: ./nox_core -v -v -i ptcp: pytutorial

Now, in your mininet terminal, rerun mininet.

Your NOX controller is running:

~/noxcore/src/nox/coreapps/examples/tutorial/pytutorial.py

Now let's see what this code does.

The code

pytutorial.py

    class pytutorial(Component):
        def __init__(self, ctxt):
            ...
        def learn_and_forward(self, dpid, inport, packet, buf, bufid):
            ...
            self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
            ...
        def packet_in_callback(self, dpid, inport, reason, len, bufid, packet):
            if not packet.parsed:
                log.debug('Ignoring incomplete packet')
            else:
                self.learn_and_forward(dpid, inport, packet, packet.arr, bufid)
            return CONTINUE
        def install(self):
            self.register_for_packet_in(self.packet_in_callback)
  

send_openflow

    def send_openflow(self, dp_id, buffer_id, packet, actions,
                      inport=openflow.OFPP_CONTROLLER):
        """\brief Send an openflow packet to a datapath.

        This function is a convenient wrapper for send_openflow_packet
        and send_openflow_buffer for situations where it is unknown in
        advance whether the packet to be sent is buffered.  If
        'buffer_id' is -1, it sends 'packet'; otherwise, it sends the
        buffer represented by 'buffer_id'.

        @param dp_id datapath to send packet to
        @param buffer_id id of buffer to send out
        @param packet data to put in openflow packet
        @param actions list of actions or dp port to send out of
        @param inport dp port to mark as source (defaults to Controller port)
        """
  

Drunk Controller

Let's implement a control app that drops half of the packet.

How to implement it?

Drunk Controller

Let's implement a control app that drops half of the packet.

How to implement it?

      from random import random
      ...
      if random() <= 0.5:
          self.send_openflow(...)
  

Learning Switch

If you know which mac address is on which port, you can packets directly to their destination.

You can extract src and dst address using:

    packet.src
    packet.dst
  

Now, log src and dst in the demo app.

Hint: src and dst are byte strings. You can covert them to string using mac_to_str.

Done? Ping your virtual machine.

Learning Switch

If you know which mac address is on which port, you can packets directly to their destination.

You can extract src and dst address using:

    packet.src
    packet.dst
  

Now, log src and dst in the demo app.

Hint: src and dst are byte strings. You can covert them to string using mac_to_str.

Done? Ping your virtual machine.

    print(mac_to_str(packet.src), "-->", mac_to_str(packet.dst))
  

Learning Switch

Now, build a dictionary of mac addresses to ports, and log its content.

To get the input port use:

    msg.in_port
  

Done? Ping your virtual machine.

Learning Switch

We are almost there...

Now, try to use your dictionary instead of using OFPP_FLOOD.

Done? Ping your virtual machine.

The final step

Pings are too slow!

Why?

What can we do?

Let's make it faster.

We need to install flow-entries on the switch.

flow entry (matched action rules) = attributes + actions

    def install_datapath_flow(self, dp_id, attrs, idle_timeout, hard_timeout,
                              actions, buffer_id=None,
                              priority=openflow.OFP_DEFAULT_PRIORITY,
                              inport=None, packet=None):
        """\brief Add a flow entry to datapath.
        @param dp_id datapath to add the entry to
        @param attrs the flow as a dictionary (described above)
        @param idle_timeout # idle seconds before flow is removed from dp
        @param hard_timeout # of seconds before flow is removed from dp
        @param actions a list where each entry is a two-element list representing
        an action.  Elem 0 of an action list should be an ofp_action_type
        and elem 1 should be the action argument (if needed). For
        OFPAT_OUTPUT, this should be another two-element list with max_len
        as the first elem, and port_no as the second
        """
  

How to install flow entries:

      # Attributes.
      attrs = {}
      attrs[core.IN_PORT] = inport
      attrs[core.DL_DST] = packet.dst

      # Actions.
      actions = [[openflow.OFPAT_OUTPUT, [0, outport]]]

      # Installs flow entries. 
      self.install_datapath_flow(dpid, attrs, 0, 0, actions)
  

Done? ping your VMS! Faster, eh?

Further reading

Mininet

OpenFlow.org

Open Networking Foundation

OpenFlow Tutorial

Thanks

Any questions?

/

#