def _activate_core(self, coreSwitchPort): """Instructs the edge switch to block every port to a core switch except the port `coreSwitchPort`. Port number between edge and core switches are in [1, nCore] Every core switch is connected to the same port on every edge switch E.g. core switch s1 will connect to port 1 on s3, s4 and s5. Parameters ---------- coreSwitchPort : int Port to the coreSwitch Returns ------- None """ ports_to_block = [ p for p in range(1, self.nCore + 1) if p != coreSwitchPort ] for port in ports_to_block: log.debug(" S{} deactivating port {}".format(self.switch_id, port)) msg = of.ofp_port_mod() msg.port_no = self.connection.ports[port].port_no msg.hw_addr = self.connection.ports[port].hw_addr msg.mask = of.OFPPC_NO_FLOOD msg.config = of.OFPPC_NO_FLOOD self.connection.send(msg) return
def _handle (event): tree = _calc_spanning_tree() try: change_count = 0 for sw, ports in tree.iteritems(): con = core.openflow.getConnection(sw) if con is None: continue # Must have disconnected tree_ports = [p[1] for p in ports] for p in con.features.ports: if p.port_no < of.OFPP_MAX: flood = p.port_no in tree_ports if not flood: if not core.openflow_discovery.isSwitchOnlyPort(sw, p.port_no): flood = True if _prev[sw][p.port_no] is flood: continue # Skip change_count += 1 _prev[sw][p.port_no] = flood #print sw,p.port_no,flood #TODO: Check results pm = of.ofp_port_mod( port_no=p.port_no, hw_addr=p.hw_addr, config = 0 if flood else of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD ) con.send(pm) if change_count: log.info("%i ports changed", change_count) except: _prev.clear() log.exception("Couldn't push spanning tree")
def port_speed(event, port, hw): msg = of.ofp_port_mod() msg.port_no = port msg.hw_addr = hw msg.advertise = of.OFPPF_10GB_FD event.connection.send(msg) print "Modified!"
def _change_port (self, dpid, port_no, down): con = core.openflow.getConnection(dpid) p = con.ports[port_no] log.info('%s' % con.ports) if down: s = 'down' else: s = 'up' log.info('change_port( dpid:%s, port_no:%s, dir:%s )' % (dpid, port_no, s)) new_state = down * of.OFPPC_PORT_DOWN new_state = of.OFPPC_PORT_DOWN \ | of.OFPPC_NO_STP \ | of.OFPPC_NO_RECV \ | of.OFPPC_NO_RECV_STP \ | of.OFPPC_NO_FLOOD \ | of.OFPPC_NO_FWD \ | of.OFPPC_NO_PACKET_IN log.info('change_port: new_state: %d %s ' % (new_state, con.info)) pm = of.ofp_port_mod( port_no=p.port_no, hw_addr=p.hw_addr, config = new_state, mask = new_state ) # of.OFPPC_PORT_DOWN ) con.send(pm) body = of.ofp_port_stats_request() body.port_no = of.OFPP_NONE # request all port statics msg = of.ofp_stats_request(body=body) con.send(msg.pack())
def _initialize(self): # The NAT mapping tables. self._nat_table = NatTable(self._packet_logger, port_map = self._config[CONFIG_KEY_PORT_MAP]) # Use a single MAC address for the NAT box. We arbitrarily choose to use the # uplink port's address. uplink_mac = self._get_mac_for_port(self._uplink_port) self._gateway_mac = EthAddr(uplink_mac) NatRouter.logger.info('Gateway MAC address: {}'.format(str(self._gateway_mac))) # Add entries to the ARP table mapping both the gateway and external NAT IP addresses to the gateway MAC address. self._arp_table.add(self._gateway_ip, self._gateway_mac) self._arp_table.add(self._nat_ip, self._gateway_mac) # Disable flooding on the uplink port. self.connection.send(of.ofp_port_mod( port_no = self._uplink_port, hw_addr = uplink_mac, config = of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD)) # Start listening to ARP add events, so we know when to process queued packets. self._arp_table.addListenerByName('ArpEntryAddedEvent', self._handle_arp_table_ArpEntryAddedEvent) super(NatRouter, self)._initialize()
def enable_flooding(self, port): msg = of.ofp_port_mod(port_no = port, hw_addr = self.connection.ports[port].hw_addr, config = 0, # opposite of of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD) self.connection.send(msg)
def _block_port(): for connection in core.openflow._connections.values(): for ports in connection.ports: if dpid==connection.dpid and ports==port and port!=65534: pm = of.ofp_port_mod(port_no=port.port_no, hw_addr = port.hw_addr, config = of.OFPPC_PORT_DOWN, mask=of.OFPPC_PORT_DOWN) connection.send(pm) times.cancel()
def _update_switch_from_spt(self, spt, active_links): # spt is a map: src_switch->set of (dst_switch, port_num) tuple for src_switch, edges_set in spt.iteritems(): con = core.openflow.getConnection(src_switch) # check that we have a valid connection to the switch if not con: continue # modify switch port's flood flag and remove flows containing invalid ports according spt. # ports in spt are enabled for flooding, others are disabled. switch_ports_in_spt = [e[1] for e in edges_set] for p in con.ports.itervalues(): if p.port_no >= of.OFPP_MAX: continue is_port_valid_for_flood = is_port_valid = p.port_no in switch_ports_in_spt #we always enable flooding for ports that are connected to hosts if not is_port_valid_for_flood and \ self._is_port_not_connected_to_switch(active_links, src_switch, p.port_no): is_port_valid_for_flood = True # make modification to port only if state was changed if self._former_port_valid_status[src_switch][p.port_no] != is_port_valid: self._former_port_valid_status[src_switch][p.port_no] = is_port_valid if is_port_valid: log.debug('Port enabled by spanning tree: dpid={}, port={}'.format(src_switch, p.port_no)) else: log.debug('Port disabled by spanning tree: dpid={}, port={}'.format(src_switch, p.port_no)) log.debug('Un-installing flows containing disabled port: dpid={}, match={{ out_port:{} }}' ' delete'.format(src_switch, p.port_no)) msg = of.ofp_flow_mod(command=of.OFPFC_DELETE, out_port=p.port_no) con.send(msg) if is_port_valid_for_flood: log.debug('flooding enabled for port: dpid={}, port={}'.format(src_switch, p.port_no)) else: log.debug('flooding disabled for port: dpid={}, port={}'.format(src_switch, p.port_no)) # send port modification message to switch configuring its flood flag config = 0 if is_port_valid_for_flood else of.OFPPC_NO_FLOOD msg = of.ofp_port_mod(port_no=p.port_no, hw_addr=p.hw_addr, mask=of.OFPPC_NO_FLOOD, config=config) con.send(msg) # notify all listeners (e.g: Tutorial objects) that port authorization has changed for listener in self._listeners[src_switch]: listener._handle_port_authorization_changed(src_switch, p.port_no, is_port_valid)
def disable_flood(self, dpid, port_no): log.debug("Disabling flooding for port {} on switch {}".format( port_no, dpidToStr(dpid))) conn = self.switches[dpid] for p in conn.ports.itervalues(): if p.port_no == port_no: msg = of.ofp_port_mod(port_no=p.port_no, hw_addr=p.hw_addr, config=of.OFPPC_NO_FLOOD, mask=of.OFPPC_NO_FLOOD) conn.send(msg) break else: log.warning("Could not find port to disable flooding")
def _send_sw_flows_no_floods(switches_set): for sw in switches_set: con = core.openflow.getConnection(sw.dpid) if con is None: log.debug('There isnt any connection between %s and controller' % sw.dpid) continue if con.connect_time is None: log.debug('Not fully connected') continue pm = of.ofp_port_mod(port_no=sw.port_number, hw_addr=dpid_port_to_mac(sw.dpid, sw.port_number, con), config=of.OFPPC_NO_FLOOD, mask=of.OFPPC_NO_FLOOD) con.send(pm)
def _set_port_status_for_every_site(switches_set): for switch in switches_set: con = core.openflow.getConnection(switch.dpid) if con is None: log.debug('There isnt any connection between %s and controller' % switch.dpid) continue if con.connect_time is None: log.debug('Not fully connected') continue if switch.active is False: send_lldp_broadcast_drop_flow (switch, con) _tag_broadcast_link(switch.dpid,switch.port_number) pm = of.ofp_port_mod(port_no=switch.port_number, hw_addr=dpid_port_to_mac(switch.dpid, switch.port_number, con), config=0 if switch.active else of.OFPPC_NO_FLOOD, mask=of.OFPPC_NO_FLOOD) con.send(pm)
def _handle_ConnectionUp (event): # When a switch connects, forget about previous port states _prev[event.dpid].clear() if _noflood_by_default: con = event.connection log.debug("Disabling flooding for %i ports", len(con.ports)) for p in con.ports.itervalues(): if p.port_no >= of.OFPP_MAX: continue _prev[con.dpid][p.port_no] = False pm = of.ofp_port_mod(port_no=p.port_no, hw_addr=p.hw_addr, config = of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD) con.send(pm) _invalidate_ports(con.dpid) if _hold_down: t = Timer(core.openflow_discovery.send_cycle_time + 1, _update_tree, kw={'force_dpid':event.dpid})
def _update_active_links(self): for link in self.links: port_no = link.local_port hw_addr = self._get_mac_for_port(port_no) # Enable flooding on active links; disable on inactive links. if link.is_active(): config_flags = 0 message = 'Enabling' else: config_flags = of.OFPPC_NO_FLOOD message = 'Disabling' SpanningTreeSwitch.logger.info('{} flooding on switch {} port {}.'.format(message, self.dpid, port_no)) port_mod = of.ofp_port_mod( port_no = port_no, hw_addr = hw_addr, config = config_flags, mask = of.OFPPC_NO_FLOOD) self.connection.send(port_mod) self._schedule_feature_refresh()
def _handle (event): # When links change, update spanning tree # Get a spanning tree tree = _calc_spanning_tree() log.debug("Spanning tree updated") # Now modify ports as needed try: change_count = 0 for sw, ports in tree.iteritems(): con = core.openflow.getConnection(sw) if con is None: continue # Must have disconnected tree_ports = [p[1] for p in ports] for p in con.ports.itervalues(): if p.port_no < of.OFPP_MAX: flood = p.port_no in tree_ports if not flood: if core.openflow_discovery.is_edge_port(sw, p.port_no): flood = True if _prev[sw][p.port_no] is flood: continue # Skip change_count += 1 _prev[sw][p.port_no] = flood #print sw,p.port_no,flood #TODO: Check results pm = of.ofp_port_mod(port_no=p.port_no, hw_addr=p.hw_addr, config = 0 if flood else of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD) con.send(pm) _invalidate_ports(con.dpid) if change_count: log.info("%i ports changed", change_count) except: _prev.clear() log.exception("Couldn't push spanning tree")
def set_flood_status(self, port_no, should_flood): # Make sure the port actually exists on the switch. hw_addr = self._get_mac_for_port(port_no) if hw_addr is None: raise Exception('Port {} does not exist on this switch ({}).'.format(port_no, self.dpid)) if should_flood: config_flags = 0 message = 'Enabling' else: config_flags = of.OFPPC_NO_FLOOD message = 'Disabling' Switch.logger.info('{} flooding on switch {} port {}.'.format(message, self.dpid, port_no)) port_mod = of.ofp_port_mod( port_no = port_no, hw_addr = hw_addr, config = config_flags, mask = of.OFPPC_NO_FLOOD) self.connection.send(port_mod) # Update our connection's view of switch port statuses. self._schedule_feature_refresh()
def _update_tree (force_dpid = None): """ Update spanning tree force_dpid specifies a switch we want to update even if we are supposed to be holding down changes. """ # Get a spanning tree tree = _calc_spanning_tree() log.debug("Spanning tree updated") # Connections born before this time are old enough that a complete # discovery cycle should have completed (and, thus, all of their # links should have been discovered). enable_time = time.time() - core.openflow_discovery.send_cycle_time - 1 # Now modify ports as needed try: change_count = 0 for sw, ports in tree.iteritems(): con = core.openflow.getConnection(sw) if con is None: continue # Must have disconnected if con.connect_time is None: continue # Not fully connected if _hold_down: if con.connect_time > enable_time: # Too young -- we should hold down changes. if force_dpid is not None and sw == force_dpid: # .. but we'll allow it anyway pass else: continue tree_ports = [p[1] for p in ports] for p in con.ports.itervalues(): if p.port_no < of.OFPP_MAX: flood = p.port_no in tree_ports if not flood: if core.openflow_discovery.is_edge_port(sw, p.port_no): flood = True if _prev[sw][p.port_no] is flood: #print sw,p.port_no,"skip","(",flood,")" continue # Skip change_count += 1 _prev[sw][p.port_no] = flood #print sw,p.port_no,flood #TODO: Check results pm = of.ofp_port_mod(port_no=p.port_no, hw_addr=p.hw_addr, config = 0 if flood else of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD) con.send(pm) _invalidate_ports(con.dpid) if change_count: log.info("%i ports changed", change_count) except: _prev.clear() log.exception("Couldn't push spanning tree")
def __flood_port_mod(self, port, flood=True): port_mod = of.ofp_port_mod(port_no=port.port_no, hw_addr=port.hw_addr, config=0 if flood else of.OFPPC_NO_FLOOD, mask=of.OFPPC_NO_FLOOD) return port_mod
def connect (self, connection): if connection is None: self.log.warn("Can't connect to nothing") return if self.dpid is None: self.dpid = connection.dpid assert self.dpid == connection.dpid if self.ports is None: self.ports = connection.features.ports self.disconnect() self.connection = connection self._listeners = self.listenTo(connection) self._connected_at = time.time() label = dpid_to_str(connection.dpid) self.log = log.getChild(label) self.log.debug("Connect %s" % (connection,)) if self._id is None: if self.dpid not in switches_by_id and self.dpid <= 254: self._id = self.dpid else: self._id = TopoSwitch._next_id TopoSwitch._next_id += 1 switches_by_id[self._id] = self self.network = IPAddr("10.%s.0.0" % (self._id,)) self.mac = dpid_to_mac(self.dpid) # Disable flooding con = connection log.debug("Disabling flooding for %i ports", len(con.ports)) for p in con.ports.itervalues(): if p.port_no >= of.OFPP_MAX: continue pm = of.ofp_port_mod(port_no=p.port_no, hw_addr=p.hw_addr, config = of.OFPPC_NO_FLOOD, mask = of.OFPPC_NO_FLOOD) con.send(pm) con.send(of.ofp_barrier_request()) con.send(of.ofp_features_request()) # Some of this is copied from DHCPD's __init__(). self.send_table() def fix_addr (addr, backup): if addr is None: return None if addr is (): return IPAddr(backup) return IPAddr(addr) self.ip_addr = IPAddr("10.%s.0.1" % (self._id,)) #self.router_addr = self.ip_addr self.router_addr = None self.dns_addr = None #fix_addr(dns_address, self.router_addr) self.subnet = IPAddr("255.0.0.0") self.pools = {} for p in connection.ports: if p < 0 or p >= of.OFPP_MAX: continue self.pools[p] = [IPAddr("10.%s.%s.%s" % (self._id,p,n)) for n in range(1,255)] self.lease_time = 60 * 60 # An hour #TODO: Actually make them expire :) self.offers = {} # Eth -> IP we offered self.leases = {} # Eth -> IP we leased