From fc13c80e86b2a9fd82f767e05a54672376b70fa7 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:08:22 -0700 Subject: [PATCH 1/9] Extend launch() docstring --- riplpox/riplpox.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index f7ca07c..fbe7524 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -504,7 +504,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 From 60f0e2b4d1a670332be2ae9a52acb9e5927991b5 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:09:39 -0700 Subject: [PATCH 2/9] Use addListeners() instead of listenTo() --- riplpox/riplpox.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index fbe7524..34081c4 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -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 @@ -65,7 +65,7 @@ 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) @@ -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 @@ -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." From c4d9272ac736aa61db2968927ea266454b1d6d56 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:11:04 -0700 Subject: [PATCH 3/9] Use None for empty buffer IDs The old code used -1 for empty buffer IDs. We now use None. --- riplpox/riplpox.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index 34081c4..e2b2989 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -72,13 +72,13 @@ def send_packet_data(self, outport, data = None): 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 @@ -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 @@ -220,7 +220,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 From 3473cc20ebe107c5dfa8f28b821f44402c84eaf5 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:11:55 -0700 Subject: [PATCH 4/9] Whitespace fixes --- riplpox/riplpox.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index e2b2989..63fae1f 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -266,9 +266,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. @@ -277,7 +277,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) @@ -288,10 +288,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: @@ -300,7 +300,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]) @@ -325,7 +325,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)) @@ -441,7 +441,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 @@ -456,15 +456,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) @@ -473,7 +473,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) From 0648a2738918bb30fdb0cd090ef8cc76f98ff426 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:13:16 -0700 Subject: [PATCH 5/9] Don't convert EthAddrs to raw for ofp_match The canonical format for ethernet addresses in POX is EthAddrs. We shouldn't convert them to raw unnecessarily. --- riplpox/riplpox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index 63fae1f..a315e40 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -180,8 +180,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 = EthAddr(src) + match.dl_dst = EthAddr(dst) dst_host_name = self.t.id_gen(dpid = dst).name_str() final_out_port, ignore = self.t.port(route[-1], dst_host_name) From d07bf5b6f697224ba45b0dbeaec5093e2760fa45 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:13:53 -0700 Subject: [PATCH 6/9] Use is_multicast instead of isMulticast() The latter is deprecated. --- riplpox/riplpox.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index a315e40..1ef5c6d 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -248,7 +248,7 @@ 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)) From e292b88b465cf0257d8ddfdcee5c71bb53160274 Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 26 Mar 2014 22:17:06 -0700 Subject: [PATCH 7/9] Deal with removed EthAddr.toInt() EthAddr.toInt() was removed, but riplpox uses the MAC-to-Mininet-name relationship, at least for catching unexpected source/destinations. (If that's all it uses them for, it's possible it should log them as warnings instead of raising an exception...) --- riplpox/riplpox.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index 1ef5c6d..1384e14 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -159,13 +159,16 @@ 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 _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()) @@ -252,9 +255,9 @@ def _handle_packet_proactive(self, event): 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?!?") From 5e9cd91d4bd896f44c354200257d3cd5938006bd Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Wed, 16 Apr 2014 20:25:27 -0700 Subject: [PATCH 8/9] Address missing EthAddr() I think when EthAddr.toInt() was removed, so was initializing from an int. This adds a helper to address the situation. --- riplpox/riplpox.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/riplpox/riplpox.py b/riplpox/riplpox.py index 1384e14..20c7814 100644 --- a/riplpox/riplpox.py +++ b/riplpox/riplpox.py @@ -162,6 +162,9 @@ def _install_reactive_path(self, event, out_dpid, final_out_port, packet): 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)) @@ -183,8 +186,8 @@ def _install_proactive_path(self, src, dst): # Form OF match match = of.ofp_match() - match.dl_src = EthAddr(src) - match.dl_dst = EthAddr(dst) + 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) From d7b50463bc98501d8c46371265db92b70b627b0c Mon Sep 17 00:00:00 2001 From: Murphy McCauley Date: Mon, 21 Apr 2014 14:39:50 -0700 Subject: [PATCH 9/9] Update INSTALL --- INSTALL | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/INSTALL b/INSTALL index 794ee70..9df6363 100644 --- a/INSTALL +++ b/INSTALL @@ -3,7 +3,7 @@ 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 ~/. @@ -11,7 +11,7 @@ The invocation examples assume that POX available in ~/. cd ~/ git clone git://github.com/noxrepo/pox cd pox -git checkout 0a1bbb8 +git checkout 105a613 # Build RipL: cd ~/