Learning POX OpenFlow controller : L2 Switch using Multiple Tables

The application name is l2_nx.py.
This module works in a reactive mode.

The idea behind this module is to introduce a feature of multiple OpenFlow tables. It is enabled by Nicira extension that allows POX to to benefit from OVS support of OpenFlow 1.2 features.
Using multiple tables for packets processing leads to much better utilization of the memory used to store rules in HW.
The functioning of this feature relies on resubmit action that is used to specify the next table to process a packet.

Module implementation is rather small and straightforward. It utilizes two tables to learn MACs.

The first thing a controller performs after a connection with a new switch is established is requesting OVS to enable such features as multiple tables and extended PacketIn format.

# Turn on Nicira packet_ins
msg = nx.nx_packet_in_format()
event.connection.send(msg)
# Turn on ability to specify table in flow_mods
msg = nx.nx_flow_mod_table_id()
event.connection.send(msg)

After that a rule to send all packets to controller is installed to the first table.

msg = nx.nx_flow_mod()
msg.priority = 1 # Low priority
msg.actions.append(of.ofp_action_output(port = of.OFPP_CONTROLLER))
msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 1))
event.connection.send(msg)

And a rule to flood all packets is installed to the second table.

msg = nx.nx_flow_mod()
msg.table_id = 1
msg.priority = 1 # Low priority
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
event.connection.send(msg)

As soon as the controller is notified (using Barrier reply) that switch has finished a described setup, handler for PacketIn events of Nicira format is activated.

event.connection.addListenerByName("PacketIn", _handle_PacketIn)

The first table is used to store source addresses. The purpose of this table is to enable data path to distinguish new MACs from learned earlier. In the first case a packet is forwarded to the controller and in the second case it is resubmitted to another table.

msg = nx.nx_flow_mod()
msg.match.of_eth_src = packet.src
msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 1))
event.connection.send(msg)

Once controller is notified on a new source MAC, it installs a rule to the second table to send packets destined to this MAC to the proper port.

msg = nx.nx_flow_mod()
msg.table_id = 1
msg.match.of_eth_dst = packet.src
msg.actions.append(of.ofp_action_output(port = event.port))
event.connection.send(msg)

Comparing to l2_pairs implementation of L2 learning switch this module optimizes usage of hardware resources.

It is not difficult to calculate the number of rules that would be installed for a topology with one switch and several hosts attached. The formula here would be two times N where N is the number of hosts. Thus for a topology of one switch and four hosts it will result in 2 * 4 = 8 rules. Output of sudo ovs-ofctl dump-flows s1 OVS command is presented below just after pingall command has been executed inside Mininet.

Rules in OVS, retrieved using sudo ovs-ofctl dump-flows s1 command, will look the following way.

 cookie=0x0, duration=18.185s, table=0, n_packets=16, n_bytes=1568, idle_age=11, priority=1 actions=CONTROLLER:65535,resubmit(,1)
 cookie=0x0, duration=10.916s, table=0, n_packets=6, n_bytes=252, idle_age=6, dl_src=fa:20:3e:ae:e7:23 actions=resubmit(,1)
 cookie=0x0, duration=10.969s, table=0, n_packets=6, n_bytes=252, idle_age=6, dl_src=56:7f:57:70:73:fb actions=resubmit(,1)
 cookie=0x0, duration=10.923s, table=0, n_packets=6, n_bytes=252, idle_age=6, dl_src=5a:0c:d5:0a:cf:dd actions=resubmit(,1)
 cookie=0x0, duration=10.945s, table=0, n_packets=6, n_bytes=252, idle_age=6, dl_src=02:a7:f3:f9:24:b5 actions=resubmit(,1)
 cookie=0x0, duration=18.185s, table=1, n_packets=19, n_bytes=1862, idle_age=10, priority=1 actions=FLOOD
 cookie=0x0, duration=10.921s, table=1, n_packets=6, n_bytes=252, idle_age=6, dl_dst=5a:0c:d5:0a:cf:dd actions=output:3
 cookie=0x0, duration=10.969s, table=1, n_packets=6, n_bytes=252, idle_age=6, dl_dst=56:7f:57:70:73:fb actions=output:1
 cookie=0x0, duration=10.944s, table=1, n_packets=6, n_bytes=252, idle_age=6, dl_dst=02:a7:f3:f9:24:b5 actions=output:2
 cookie=0x0, duration=10.913s, table=1, n_packets=6, n_bytes=252, idle_age=6, dl_dst=fa:20:3e:ae:e7:23 actions=output:4

New things that appeared in this module

  • call_when_ready allows to wait until another module is loaded and executed
  • nx_packet_in_format allows OVS to send packets in an extended format
  • nx_flow_mod_table_id notifies OVS that multiple tables will be programmed by controller
  • nx_action_resubmit – resubmit action needed to specify the next table
  • nx_flow_mod – extended flow_mod with table identifier support

References