Net App 4 – simple switching hub using Ryu controller

In this section, you will be learning about how a simple switch hub functions based on instructions on the Ryu controller. We shall be using the SDN hub starter kit VM in Chapter 5Setting Up the Environment, which has the Ryu controller along with Mininet.
The switching hub, which shall be covered in this section, has various capabilities:

  • The ability to learn and retain the MAC addresses of hosts connected to any of its ports
  • The ability to forward packets to the port of a host whose MAC address has been learned earlier
  • The ability to flood packets on all its ports except the incoming ports for packets whose destination MAC address is not present in the MAC address table

In a simple switching hub, the MAC address uses the packet-in function of OpenFlow. This is used by the controller to receive the packet from the switch. These packets are analyzed by the switch where the MAC address is being learned based on the host and the port to which it is connected. Upon analysis, the switch must process the packets based on the MAC address and the MAC address table present in the switch:

  • If the destination MAC address is present, the switch uses a packet-out function to forward the packet to the destination host
  • If the destination MAC address is not present, flooding is done using the packet-out function

The switching hub can be found in this directory in RYU: ryu/app/example_switch_13.py. The simple switch used in this demonstrations supports OpenFlow 1.3.

The switching hub code (example_switch_l3.py) begins with class definition and initialization:

class ExampleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(ExampleSwitch13, self).__init__(*args, **kwargs)
# initialize mac address table.
self.mac_to_port = {}

The ryu.base.app_manager.RyuApp is inherited in order to function as a Ryu application. The ofproto_v1_3.OFP_VERSION is used to define the OpenFlow 1.3 version. Next is mac_to_port, which defines the MAC address table. Also, self.mac_to_port = {} defines an empty dictionary that would be used later.

The event handler is then defined and implemented by the Ryu application upon receipt of an OpenFlow message. This event handler defines a function with the event object for the argument and uses the ryu.controller.handler.set_ev_cls decorator to decorate. The set_ev_cls specifies the event class supporting the received message and the state of the OpenFlow switch for the argument. The event class name is ryu.controller.ofp_event.EventOFP + < The OpenFlow message name>.
For instance, the packet-in message becomes EventOFPPacketIn. Various events listed in the earlier chapters can be substituted here:

@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser

The table-miss flow entry is added to the flow table in preparation to receive the packet-in message once the table-miss flow entry is added upon a handshake with the OpenFlow switch.

The instance of the OpenFlow message class corresponding to the event is stored in ev.msg. Here it is ryu.ofproto.ofproto_v1_3_parser.OFPSwitchFeatures.
In msg.datapath, the instance of the ryu.controller.controller.datapath class corresponding to the OpenFlow switch that issued this message is stored. Essential processing, such as actual communication with the OpenFlow switch and issuance of the event corresponding to the received message, is performed by the datapath class.

The key attributes used by the Ryu applications are as follows:

  • The ID that defines the data path ID of the connected OpenFlow switch
  • Ofproto, which indicates the ofproto module that supports the OpenFlow version, is in use
  • ofproto_parser defines the ofproto_parser module
def switch_features_handler(self, ev):
# install the table-miss flow entry.
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)

In the instruction of this entry, where the table-miss flow has the lowest priority (0) that matches all the packets and the action is specified to send to the controller port when the packet matches no normal flow entry, the packet-in is issued.

The OFPMatch class is used to match all packets. Transfer to the controller port is done using the output action class, OFPActionOutput. The controller is specified as the output destination and OFPCML_NO_BUFFER is specified to max_len in order for z to send all packets to the controller. Finally, 0 (lowest) is specified for priority and the add_flow() method is executed to send the flow mod message:

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser

The preceding handler (packet-in event) is used to accept received packets whose MAC address is not known:

def _packet_in_handler(self, ev):
# ...
# get the received port number from packet_in message.
in_port = msg.match['in_port']
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
# ...

The receive port (in_port) is gotten from the OFPPacketIn match, while the sender MAC address and destination MAC address is gotten from the Ethernet header of the received packets using Ryu's packet library.

The MAC address table is then updated based on the port and MAC address of the sender.
In order to support connection with multiple OpenFlow switches, the MAC address table is so designed to be managed for each OpenFlow switch. The datapath ID is used to identify the OpenFlow switches:

def _packet_in_handler(self, ev):
# ...
# if the destination mac address is already learned,
# decide which port to output the packet, otherwise FLOOD.
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD

# construct action list.
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time.
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
# ...

Based on the preceding portion, an entry is added to the flow table of the OpenFlow switch where the MAC address is found:

def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# construct flow_mod message and send it.
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
# ...

Here, the processing of the packet-in handler occurs.

For flow entries, set a match that indicates the target packet conditions and instructions that indicate the operation on the packet, entry priority level, and effective time:

def add_flow(self, datapath, priority, match, actions):
# ...
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)

The entry then needs to be added to the flow table by issuing the flow mod message:

def _packet_in_handler(self, ev):
# ...
# construct packet_out message and send it.
out = parser.OFPPacketOut(datapath=datapath,
buffer_id=ofproto.OFP_NO_BUFFER,
in_port=in_port, actions=actions,
data=msg.data)
datapath.send_msg(out)

Finally, irrespective of whether the destination MAC address is found from the MAC address table, at the end, the packet-out message is issued and received packets are transferred.

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

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