Running a POX application

After getting the POX controller, you can try running a basic hub example in POX as follows:

    $ cd pox
$./pox.py log.level --DEBUG misc.of_tutorial

This command line tells POX to enable verbose logging and to start the of_tutorial component, which you will be using. This of_tutorial component acts as an Ethernet hub. Now you can start the Mininet OpenFlow laboratory using the following command line:

    $ sudo mn --topo single,3 --mac --switch ovsk --controller remote  

The switches may take a little bit of time to connect. When an OpenFlow switch loses its connection to a controller, it will generally increase the period between which it attempts to contact the controller, up to a maximum of 15 seconds. This timer is implementation specific and can be defined by the user. Since the OpenFlow switch has not connected yet, this delay may be anything between 0 and 15 seconds. If this is too long to wait, the switch can be configured to wait no more than N seconds using the --max-backoff parameter. Wait until the application indicates that the OpenFlow switch has connected. When the switch connects, POX will print something like the following:

    INFO:openflow.of_01:[Con 1/1] Connected to 00-00-00-00-00-01
    DEBUG:samples.of_tutorial:Controlling [Con 1/1]  

The first line is the portion of POX that handles OpenFlow connections. The second line is the tutorial component itself.

Now, we verify that the hosts can ping each other and that all the hosts see the exact same traffic: the behavior of a hub. To do this, we will create xterms for each host and view the traffic in each. In the Mininet console, start up three xterms:

    mininet> xterm h1 h2 h3  

Arrange each xterm so that they're all on the screen at once. This may require reducing the height to fit on a cramped laptop screen. In the xterms for h2 and h3, run tcpdump, a utility to print the packets seen by a host:

    # tcpdump -XX -n -i h2-eth0 
# tcpdump -XX -n -i h3-eth0

In the xterm for h1, issue a ping command:

    # ping -c1 10.0.0.2  

The ping packets are now going up to the controller, which then floods them out of all interfaces except the sending one. You should see identical ARP and ICMP packets corresponding to the ping in both xterms running tcpdump. This is how a hub works: it sends all packets to every port on the network. Now, see what happens when a non-existent host doesn't reply. From the h1 xterm:

    # ping -c1 10.0.0.5  

You should see three unanswered ARP requests in the tcpdump xterms. If your code is off later, three unanswered ARP requests is a signal that you might be accidentally dropping packets. You can close the xterms now.

In order to change the behavior of the hub to a learning switch, you have to add the learning switch functionality to of_tutorial.py. Go to your SSH terminal and stop the tutorial hub controller by pressing Ctrl + C. The file you'll modify is pox/misc/of_tutorial.py. Open pox/misc/of_tutorial.py in your favorite editor. The current code calls act_like_hub() from the handler for packet_in messages to implement the switch behavior. You will want to switch to using the act_like_switch() function, which contains a sketch of what your final learning switch code should look like. Each time you change and save this file, make sure to restart POX, then use pings to verify the behavior of the combination of switch and controller as the following:

  • Hub
  • Controller-based Ethernet learning switch
  • Flow-accelerated learning switch

For the second and third use cases, hosts that are not the destination for a ping should display no tcpdump traffic after the initial broadcast ARP request. Python is a dynamic and interpreted language. There is no separate compilation step; just update your code and rerun it. Python has built-in hash tables, called dictionaries, and vectors, called lists. Some of the common operations that you need for a learning switch are as follows:

  • To initialize a dictionary:
      mactable = {} 
  • To add an element to a dictionary:
      mactable[0x123] = 2
  • To check for dictionary membership:
      if 0x123 in mactable: 
          print 'element 2 is in mactable' 
      if 0x123 not in mactable: 
          print 'element 2 is not in mactable' 
  • To print a debug message in POX:
      log.debug('saw new MAC!') 
  • To print an error message in POX:
      log.error('unexpected packet causing system meltdown!') 
  • To print all member variables and functions of an object:
      print dir(object) 
  • To comment a line of code:
      # Prepend comments with a #; no // or /**/ 
You can find more Python resources at the following URLs:

In addition to the preceding functions, you also need some details about the POX APIs, which are useful for the development of learning switch. There is also other documentation available in the appropriate section of POX's website.

Sending OpenFlow messages with POX:

connection.send( ... ) # send an OpenFlow message to a switch 

When a connection to a switch starts, a ConnectionUp event is fired. The example code creates a new Tutorial object that holds a reference to the associated Connection object. This can later be used to send commands (OpenFlow messages) to the switch:

ofp_action_output class 

This is an action for use with ofp_packet_out and ofp_flow_mod. It specifies a switch port that you wish to send the packet out of. It can also take various special port numbers. An example of this would be OFPP_FLOOD, which sends the packet out on all ports except the one the packet originally arrived on. The following example creates an output action that would send packets to all ports:

out_action = of.ofp_action_output(port = of.OFPP_FLOOD) 
ofp_match class 

Objects of this class describe packet header fields and an input port to match on. All fields are optional; items that are not specified are wildcards, and will match on anything. Some notable fields of ofp_match objects are:

  • dl_src: The data link layer (MAC) source address
  • dl_dst: The data link layer (MAC) destination address
  • in_port: The packet input switch port

For example: Create a match that matches packets arriving on port 3:

match = of.ofp_match() 
match.in_port = 3 
ofp_packet_out OpenFlow message 

The ofp_packet_out message instructs a switch to send a packet. The packet might be constructed at the controller, or it might be the one that the switch received, buffered, and forwarded to the controller (and is now referenced by a buffer_id). Notable fields are:

  • buffer_id: The buffer_id of a buffer you wish to send. Do not set if you are sending a constructed packet.
  • data: Raw bytes you wish the switch to send. Do not set if you are sending a buffered packet.
  • actions: A list of actions to apply (for this tutorial, this is just a single ofp_action_output action).
  • in_port: The port number this packet initially arrived on if you are sending by buffer_id, otherwise OFPP_NONE.

For example: The send_packet() method of_tutorial:

 def send_packet (self, buffer_id, raw_data, out_port, in_port): 
   """ 
   Sends a packet out of the specified switch port. 
   If buffer_id is a valid buffer on the switch, use that. 
Otherwise, send the raw data in raw_data. The "in_port" is the port number that packet arrived on. Use OFPP_NONE if you're generating this packet. """ msg = of.ofp_packet_out() msg.in_port = in_port if buffer_id != -1 and buffer_id is not None: # We got a buffer ID from the switch; use that msg.buffer_id = buffer_id else: # No buffer ID from switch -- we got the raw data if raw_data is None: # No raw_data specified -- nothing to send! return msg.data = raw_data action = of.ofp_action_output(port = out_port) msg.actions.append(action) # Send message to switch self.connection.send(msg) ofp_flow_mod OpenFlow message

This instructs a switch to install a flow table entry. Flow table entries match some fields of the incoming packets and execute some list of actions on the matching packets. The actions are the same as for ofp_packet_out, mentioned previously (and again, for the tutorial, all you need is the simple ofp_action_output action). The match is described by an ofp_match object. Notable fields are:

  • idle_timeout: Number of idle seconds before the flow entry is removed. Defaults to no idle timeout.
  • hard_timeout: Number of seconds before the flow entry is removed. Defaults to no timeout.
  • actions: A list of actions to be performed on matching packets (for example, ofp_action_output).
  • priority: When using non-exact (wildcarded) matches, this specifies the priority for overlapping matches. Higher values have higher priority. Not important for exact or non-overlapping entries.
  • buffer_id: The buffer_id field of a buffer to apply the actions to immediately. Leave unspecified for none.
  • in_port: If using a buffer_id, this is the associated input port.
  • match: An ofp_match object. By default, this matches everything, so you should probably set some of its fields.

For example: Create a flow_mod that sends packets from port 3 out of port 4:

fm = of.ofp_flow_mod() 
fm.match.in_port = 3 
fm.actions.append(of.ofp_action_output(port = 4)) 
For more information about OpenFlow constants, see the main OpenFlow types/enums/structs file, openflow.h, in ~/openflow/include/openflow/openflow.h. You may also wish to consult POX's OpenFlow library in pox/openflow/libopenflow_01.py and, of course, the OpenFlow 1.0 specification.

The POX packet library is used to parse packets and make each protocol field available to Python. This library can also be used to construct packets for sending. The parsing libraries are present in pox/lib/packet/.

Each protocol has a corresponding parsing file. For the first exercise, you'll only need to access the Ethernet source and destination fields. To extract the source of a packet, use the dot notation:

packet.src 

The Ethernet src and dst fields are stored as pox.lib.addresses.EthAddr objects. These can easily be converted to their common string representation (str(addr) will return something like "01:ea:be:02:05:01"), or be created from their common string representation (EthAddr("01:ea:be:02:05:01")). To see all members of a parsed packet object:

print dir(packet) 

Here's what you'd see for an ARP packet:

['HW_TYPE_ETHERNET', 'MIN_LEN', 'PROTO_TYPE_IP', 'REPLY', 'REQUEST', 'REV_REPLY', 
 'REV_REQUEST', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
 '__getattribute__', '__hash__', '__init__', '__len__', '__module__', '__new__', 
 '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', 
 '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_init', 'err', 
 'find', 'hdr', 'hwdst', 'hwlen', 'hwsrc', 'hwtype', 'msg', 'next', 'opcode', 
 'pack', 'parse', 'parsed', 'payload', 'pre_hdr', 'prev', 'protodst', 'protolen', 
 'protosrc', 'prototype', 'raw', 'set_payload', 'unpack', 'warn'] 

Many fields are common to all the Python objects and can be ignored, but this can be a quick way to avoid a trip to a function's documentation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset