Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ RipL-POX (Ripcord-Lite for POX): A simple network controller for OpenFlow-based
== Install ==
RipL, POX, and setuptools are the dependencies.

This version has been tested with the master branch of POX, commit 0a1bbb8, made on Sat Nov 24 01:52:07 2012 -0800.
This version has been tested with the dart branch of POX, commit 105a613, made on Fri Apr 18 16:00:55 2014 -0700.

The invocation examples assume that POX available in ~/.

# Add POX at tested version:
cd ~/
git clone git://github.com/noxrepo/pox
cd pox
git checkout 0a1bbb8
git checkout 105a613

# Build RipL:
cd ~/
Expand Down
64 changes: 37 additions & 27 deletions riplpox/riplpox.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@


# Borrowed from pox/forwarding/l2_multi
class Switch (EventMixin):
class Switch (object):
def __init__ (self):
self.connection = None
self.ports = None
Expand All @@ -65,20 +65,20 @@ def connect (self, connection):
self.disconnect()
log.debug("Connect %s" % (connection,))
self.connection = connection
self._listeners = self.listenTo(connection)
self._listeners = connection.addListeners(self)

def send_packet_data(self, outport, data = None):
msg = of.ofp_packet_out(in_port=of.OFPP_NONE, data = data)
msg.actions.append(of.ofp_action_output(port = outport))
self.connection.send(msg)

def send_packet_bufid(self, outport, buffer_id = -1):
def send_packet_bufid(self, outport, buffer_id = None):
msg = of.ofp_packet_out(in_port=of.OFPP_NONE)
msg.actions.append(of.ofp_action_output(port = outport))
msg.buffer_id = buffer_id
self.connection.send(msg)

def install(self, port, match, buf = -1, idle_timeout = 0, hard_timeout = 0,
def install(self, port, match, buf = None, idle_timeout = 0, hard_timeout = 0,
priority = of.OFP_DEFAULT_PRIORITY):
msg = of.ofp_flow_mod()
msg.match = match
Expand All @@ -89,7 +89,7 @@ def install(self, port, match, buf = -1, idle_timeout = 0, hard_timeout = 0,
msg.buffer_id = buf
self.connection.send(msg)

def install_multiple(self, actions, match, buf = -1, idle_timeout = 0,
def install_multiple(self, actions, match, buf = None, idle_timeout = 0,
hard_timeout = 0, priority = of.OFP_DEFAULT_PRIORITY):
msg = of.ofp_flow_mod()
msg.match = match
Expand All @@ -109,7 +109,7 @@ def _handle_ConnectionDown (self, event):
def sep():
log.info("************************************************")

class RipLController(EventMixin):
class RipLController(object):

def __init__ (self, t, r, mode):
self.switches = {} # Switches seen: [dpid] -> Switch
Expand All @@ -120,7 +120,7 @@ def __init__ (self, t, r, mode):

# TODO: generalize all_switches_up to a more general state machine.
self.all_switches_up = False # Sequences event handling.
self.listenTo(core.openflow, priority=0)
core.openflow.addListeners(self, priority=0)

def _raw_dpids(self, arr):
"Convert a list of name strings (from Topo object) to numbers."
Expand Down Expand Up @@ -159,13 +159,19 @@ def _install_reactive_path(self, event, out_dpid, final_out_port, packet):
self.switches[node_dpid].install(out_port, match, idle_timeout =
IDLE_TIMEOUT)

def _eth_to_int(self, eth):
return sum(([ord(x)*2**((5-i)*8) for i,x in enumerate(eth.raw)]))

def _int_to_eth(self, inteth):
return EthAddr("%012x" % (inteth,))

def _src_dst_hash(self, src_dpid, dst_dpid):
"Return a hash based on src and dst dpids."
return crc32(pack('QQ', src_dpid, dst_dpid))

def _install_proactive_path(self, src, dst):
"""Install entries on route between two hosts based on MAC addrs.

src and dst are unsigned ints.
"""
src_sw = self.t.up_nodes(self.t.id_gen(dpid = src).name_str())
Expand All @@ -180,8 +186,8 @@ def _install_proactive_path(self, src, dst):

# Form OF match
match = of.ofp_match()
match.dl_src = EthAddr(src).toRaw()
match.dl_dst = EthAddr(dst).toRaw()
match.dl_src = self._int_to_eth(src)
match.dl_dst = self._int_to_eth(dst)

dst_host_name = self.t.id_gen(dpid = dst).name_str()
final_out_port, ignore = self.t.port(route[-1], dst_host_name)
Expand Down Expand Up @@ -220,7 +226,7 @@ def _flood(self, event):
# self.switches[sw].send_packet_bufid(port, event.ofp.buffer_id)
#else:
self.switches[sw].send_packet_data(port, event.data)
# buffer_id = -1
# buffer_id = None

def _handle_packet_reactive(self, event):
packet = event.parsed
Expand Down Expand Up @@ -248,13 +254,13 @@ def _handle_packet_reactive(self, event):
def _handle_packet_proactive(self, event):
packet = event.parse()

if packet.dst.isMulticast():
if packet.dst.is_multicast:
self._flood(event)
else:
hosts = self._raw_dpids(self.t.layer_nodes(self.t.LAYER_HOST))
if packet.src.toInt() not in hosts:
if self._eth_to_int(packet.src) not in hosts:
raise Exception("unrecognized src: %s" % packet.src)
if packet.dst.toInt() not in hosts:
if self._eth_to_int(packet.dst) not in hosts:
raise Exception("unrecognized dst: %s" % packet.dst)
raise Exception("known host MACs but entries weren't pushed down?!?")

Expand All @@ -266,9 +272,9 @@ def dpid_port_to_host_index(self, dpid, port):
def _install_hybrid_dynamic_flows(self, event, out_dpid, final_out_port, packet):
"Install entry at ingress switch."
in_name = self.t.id_gen(dpid = event.dpid).name_str()
#log.info("in_name: %s" % in_name)
#log.info("in_name: %s" % in_name)
out_name = self.t.id_gen(dpid = out_dpid).name_str()
#log.info("out_name: %s" % out_name)
#log.info("out_name: %s" % out_name)
hash_ = self._ecmp_hash(packet)
src_dst_route = self.r.get_route(in_name, out_name, hash_)
# Choose a random core switch.
Expand All @@ -277,7 +283,7 @@ def _install_hybrid_dynamic_flows(self, event, out_dpid, final_out_port, packet)
core_sw_id = self.t.id_gen(dpid = core_sw)
core_sw_name = self.t.id_gen(dpid = core_sw).name_str()

route = self.r.get_route(in_name, core_sw_name, None)
route = self.r.get_route(in_name, core_sw_name, None)
assert len(route) == 3
log.info("route: %s" % route)

Expand All @@ -288,10 +294,10 @@ def _install_hybrid_dynamic_flows(self, event, out_dpid, final_out_port, packet)
#log.info("core_sw_index: %s" % core_sw_index)

dst_host_index = self.dpid_port_to_host_index(out_dpid, final_out_port)
#log.info("dst_host_index: %s" % dst_host_index)
#log.info("dst_host_index: %s" % dst_host_index)

vlan = (dst_host_index << 2) + core_sw_index
log.info("vlan: %s" % vlan)
log.info("vlan: %s" % vlan)
log.info("len(src_dst_route): %i" % len(src_dst_route))

if len(src_dst_route) == 1:
Expand All @@ -300,7 +306,7 @@ def _install_hybrid_dynamic_flows(self, event, out_dpid, final_out_port, packet)
(match.dl_src, match.dl_dst, in_name))
self.switches[event.dpid].install(final_out_port, match, idle_timeout =
HYBRID_IDLE_TIMEOUT,
priority = PRIO_HYBRID_FLOW_DOWN)
priority = PRIO_HYBRID_FLOW_DOWN)
else:
# Write VLAN and send up
src_port, dst_port = self.t.port(route[0], route[1])
Expand All @@ -325,7 +331,7 @@ def _handle_packet_hybrid(self, event):
# Insert flow, deliver packet directly to destination.
if packet.dst in self.macTable:
out_dpid, out_port = self.macTable[packet.dst]
log.info("found %s on dpid %s, port %s" % (packet.dst, out_dpid, out_port))
log.info("found %s on dpid %s, port %s" % (packet.dst, out_dpid, out_port))
self._install_hybrid_dynamic_flows(event, out_dpid, out_port, packet)

#log.info("sending to entry in mactable: %s %s" % (out_dpid, out_port))
Expand Down Expand Up @@ -441,7 +447,7 @@ def _install_hybrid_static_flows(self):
# edge_port, agg_port = self.t.port(edge_sw_name, agg_sw_name)
# log.info("adding entry from %s to %s via VLAN %i and port %i" %
# (edge_sw_name, agg_sw_name, match.dl_vlan, edge_port))
# self.switches[edge_sw].install(edge_port, match,
# self.switches[edge_sw].install(edge_port, match,
# priority = PRIO_HYBRID_VLAN_UP)

# Add one flow entry for each agg switch pointing up
Expand All @@ -456,15 +462,15 @@ def _install_hybrid_static_flows(self):
if agg_sw_name in self.t.g[core_sw_name]:
# If connected, add entry.
agg_port, core_port = self.t.port(agg_sw_name, core_sw_name)

# Form OF match
match = of.ofp_match()
# Highest-order four bits are host index

# Lowest-order two bits are core switch ID
core_sw_id = self.t.id_gen(dpid = core_sw)
core_index = (core_sw_id.sw - 1) * 2 + (core_sw_id.host - 1)

for host_index in range((self.t.k ** 3) / 4):
match.dl_vlan = (host_index << 2) + core_index
#log.info("vlan: %s" % match.dl_vlan)
Expand All @@ -473,7 +479,7 @@ def _install_hybrid_static_flows(self):
(agg_sw_name, core_sw_name, match.dl_vlan, agg_port))
self.switches[agg_sw].install(agg_port, match,
priority = PRIO_HYBRID_VLAN_UP)


def _handle_ConnectionUp (self, event):
sw = self.switches.get(event.dpid)
Expand Down Expand Up @@ -504,7 +510,11 @@ def _handle_ConnectionUp (self, event):

def launch(topo = None, routing = None, mode = None):
"""
Args in format toponame,arg1,arg2,...
Launch RipL-POX

topo is in format toponame,arg1,arg2,...
routing is a routing type (e.g., st, random, hashed)
mode is a controller mode (e.g., proactive, reactive, hybrid)
"""
if not mode:
mode = DEF_MODE
Expand Down