def port_status_handler(self, ev): msg = ev.msg reason = msg.reason datapath = msg.datapath port = msg.desc ofproto = datapath.ofproto if reason == ofproto.OFPPR_ADD: LOG.debug( 'DPSET: A port was added.' + '(datapath id = %s, port number = %s)', dpid_to_str(datapath.id), port.port_no) self._port_added(datapath, port) self.send_event_to_observers(EventPortAdd(datapath, port)) elif reason == ofproto.OFPPR_DELETE: LOG.debug( 'DPSET: A port was deleted.' + '(datapath id = %s, port number = %s)', dpid_to_str(datapath.id), port.port_no) self._port_deleted(datapath, port) self.send_event_to_observers(EventPortDelete(datapath, port)) else: assert reason == ofproto.OFPPR_MODIFY LOG.debug( 'DPSET: A port was modified.' + '(datapath id = %s, port number = %s)', dpid_to_str(datapath.id), port.port_no) self.port_state[datapath.id].modify(port.port_no, port) self.send_event_to_observers(EventPortModify(datapath, port))
def packet_in_handler(self, ev): self.logger.debug('packet_in_handler') msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto # TODO: subscribe only the designated datapath dpid = datapath.id if dpid != self.interface.dpid: self.logger.debug('packet_in_handler dpid %s %s', dpid_lib.dpid_to_str(dpid), dpid_lib.dpid_to_str(self.interface.dpid)) return in_port = None for field in msg.match.fields: if field.header == ofproto.OXM_OF_IN_PORT: in_port = field.value break if in_port != self.interface.port_no: self.logger.debug('packet_in_handler in_port %s %s', in_port, self.interface.port_no) return self._send_vrrp_packet_received(msg.data)
def _do_lacp(self, req_lacp, src, msg): """packet-in process when the received packet is LACP.""" datapath = msg.datapath dpid = datapath.id ofproto = datapath.ofproto parser = datapath.ofproto_parser if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: port = msg.in_port else: port = msg.match['in_port'] self.logger.info("SW=%s PORT=%d LACP received.", dpid_to_str(dpid), port) self.logger.debug(str(req_lacp)) # when LACP arrived at disabled port, update the status of # the slave i/f to enabled, and send a event. if not self._get_slave_enabled(dpid, port): self.logger.info("SW=%s PORT=%d the slave i/f has just been up.", dpid_to_str(dpid), port) self._set_slave_enabled(dpid, port, True) self.send_event_to_observers( EventSlaveStateChanged(datapath, port, True)) # set the idle_timeout time using the actor state of the # received packet. if req_lacp.LACP_STATE_SHORT_TIMEOUT == \ req_lacp.actor_state_timeout: idle_timeout = req_lacp.SHORT_TIMEOUT_TIME else: idle_timeout = req_lacp.LONG_TIMEOUT_TIME # when the timeout time has changed, update the timeout time of # the slave i/f and re-enter a flow entry for the packet from # the slave i/f with idle_timeout. if idle_timeout != self._get_slave_timeout(dpid, port): self.logger.info("SW=%s PORT=%d the timeout time has changed.", dpid_to_str(dpid), port) self._set_slave_timeout(dpid, port, idle_timeout) func = self._add_flow.get(ofproto.OFP_VERSION) assert func func(src, port, idle_timeout, datapath) # create a response packet. res_pkt = self._create_response(datapath, port, req_lacp) # packet-out the response packet. out_port = ofproto.OFPP_IN_PORT actions = [parser.OFPActionOutput(out_port)] out = datapath.ofproto_parser.OFPPacketOut( datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, data=res_pkt.data, in_port=port, actions=actions) datapath.send_msg(out)
def _get_bridge_name(self): """ get Bridge name of a given 'datapath_id' """ command = ovs_vsctl.VSCtlCommand( 'find', ('Bridge', 'datapath_id=%s' % dpid_lib.dpid_to_str(self.datapath_id))) self.run_command([command]) if not isinstance(command.result, list) or len(command.result) != 1: raise OVSBridgeNotFound( datapath_id=dpid_lib.dpid_to_str(self.datapath_id)) return command.result[0].name
def _create_lacp(self, datapath, port, req): """create a LACP packet.""" actor_system = datapath.ports[datapath.ofproto.OFPP_LOCAL].hw_addr res = slow.lacp( actor_system_priority=0xffff, actor_system=actor_system, actor_key=req.actor_key, actor_port_priority=0xff, actor_port=port, actor_state_activity=req.LACP_STATE_PASSIVE, actor_state_timeout=req.actor_state_timeout, actor_state_aggregation=req.actor_state_aggregation, actor_state_synchronization=req.actor_state_synchronization, actor_state_collecting=req.actor_state_collecting, actor_state_distributing=req.actor_state_distributing, actor_state_defaulted=req.LACP_STATE_OPERATIONAL_PARTNER, actor_state_expired=req.LACP_STATE_NOT_EXPIRED, partner_system_priority=req.actor_system_priority, partner_system=req.actor_system, partner_key=req.actor_key, partner_port_priority=req.actor_port_priority, partner_port=req.actor_port, partner_state_activity=req.actor_state_activity, partner_state_timeout=req.actor_state_timeout, partner_state_aggregation=req.actor_state_aggregation, partner_state_synchronization=req.actor_state_synchronization, partner_state_collecting=req.actor_state_collecting, partner_state_distributing=req.actor_state_distributing, partner_state_defaulted=req.actor_state_defaulted, partner_state_expired=req.actor_state_expired, collector_max_delay=0) self.logger.info("SW=%s PORT=%d LACP sent.", dpid_to_str(datapath.id), port) self.logger.debug(str(res)) return res
def _configure_vrrp_router(self, vrrp_version, priority, ip_addr, switch_index, vrid): switches = self.switches self.logger.debug('%s', switches.dps) dpid = sorted(switches.dps.keys())[switch_index] self.logger.debug('%s', lib_dpid.dpid_to_str(dpid)) self.logger.debug('%s', switches.port_state) # hack: use the smallest port no to avoid picking OVS local port port_no = sorted(switches.port_state[dpid].keys())[0] self.logger.debug('%d', port_no) port = switches.port_state[dpid][port_no] self.logger.debug('%s', port) mac = port.hw_addr self.logger.debug('%s', mac) interface = vrrp_event.VRRPInterfaceOpenFlow( mac, ip_addr, None, dpid, port_no) self.logger.debug('%s', interface) config = vrrp_event.VRRPConfig( version=vrrp_version, vrid=vrid, priority=priority, ip_addresses=[ip_addr]) self.logger.debug('%s', config) rep = vrrp_api.vrrp_config(self, interface, config) self.logger.debug('%s', rep) return rep
def __init__(self, dp, logger, config, send_ev_func): super(Bridge, self).__init__() self.dp = dp self.logger = logger self.dpid_str = {'dpid': dpid_to_str(dp.id)} self.send_event = send_ev_func # Bridge data bridge_conf = config.get('bridge', {}) values = self._DEFAULT_VALUE for key, value in bridge_conf.items(): values[key] = value system_id = list(dp.ports.values())[0].hw_addr self.bridge_id = BridgeId(values['priority'], values['sys_ext_id'], system_id) self.bridge_times = Times( 0, # message_age values['max_age'], values['hello_time'], values['fwd_delay']) # Root bridge data self.root_priority = Priority(self.bridge_id, 0, None, None) self.root_times = self.bridge_times # Ports self.ports = {} self.ports_state = {} self.ports_conf = config.get('ports', {}) for ofport in dp.ports.values(): self.port_add(ofport) # Install BPDU PacketIn flow. (OpenFlow 1.2/1.3) if dp.ofproto == ofproto_v1_2 or dp.ofproto == ofproto_v1_3: ofctl = OfCtl_v1_2later(self.dp) ofctl.add_bpdu_pkt_in_flow()
def packet_in_handler(self, req_pkt, req_igmp, msg): """the process when the snooper received IGMP.""" dpid = msg.datapath.id ofproto = msg.datapath.ofproto if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: in_port = msg.in_port else: in_port = msg.match['in_port'] log = "SW=%s PORT=%d IGMP received. " % (dpid_to_str(dpid), in_port) self.logger.debug(str(req_igmp)) if igmp.IGMP_TYPE_QUERY == req_igmp.msgtype: self.logger.info(log + "[QUERY]") (req_ipv4, ) = req_pkt.get_protocols(ipv4.ipv4) (req_eth, ) = req_pkt.get_protocols(ethernet.ethernet) self._do_query(req_igmp, req_ipv4, req_eth, in_port, msg) elif (igmp.IGMP_TYPE_REPORT_V1 == req_igmp.msgtype or igmp.IGMP_TYPE_REPORT_V2 == req_igmp.msgtype): self.logger.info(log + "[REPORT]") self._do_report(req_igmp, in_port, msg) elif igmp.IGMP_TYPE_LEAVE == req_igmp.msgtype: self.logger.info(log + "[LEAVE]") self._do_leave(req_igmp, in_port, msg) elif igmp.IGMP_TYPE_REPORT_V3 == req_igmp.msgtype: self.logger.info(log + "V3 is not supported yet.") self._do_flood(in_port, msg) else: self.logger.info(log + "[unknown type:%d]", req_igmp.msgtype) self._do_flood(in_port, msg)
def _register(self, dp): LOG.debug('DPSET: register datapath %s', dp) assert dp.id is not None # while dpid should be unique, we need to handle duplicates here # because it's entirely possible for a switch to reconnect us # before we notice the drop of the previous connection. # in that case, # - forget the older connection as it likely will disappear soon # - do not send EventDP leave/enter events # - keep the PortState for the dpid send_dp_reconnected = False if dp.id in self.dps: self.logger.warning('DPSET: Multiple connections from %s', dpid_to_str(dp.id)) self.logger.debug('DPSET: Forgetting datapath %s', self.dps[dp.id]) (self.dps[dp.id]).close() self.logger.debug('DPSET: New datapath %s', dp) send_dp_reconnected = True self.dps[dp.id] = dp if dp.id not in self.port_state: self.port_state[dp.id] = PortState() ev = EventDP(dp, True) with warnings.catch_warnings(): warnings.simplefilter('ignore') for port in dp.ports.values(): self._port_added(dp, port) ev.ports.append(port) self.send_event_to_observers(ev) if send_dp_reconnected: ev = EventDPReconnected(dp) ev.ports = self.port_state.get(dp.id, {}).values() self.send_event_to_observers(ev)
def lldp_packet(dpid, port_no, dl_addr, ttl): pkt = packet.Packet() dst = lldp.LLDP_MAC_NEAREST_BRIDGE src = dl_addr ethertype = ETH_TYPE_LLDP eth_pkt = ethernet.ethernet(dst, src, ethertype) pkt.add_protocol(eth_pkt) tlv_chassis_id = lldp.ChassisID( subtype=lldp.ChassisID.SUB_LOCALLY_ASSIGNED, chassis_id=(LLDPPacket.CHASSIS_ID_FMT % dpid_to_str(dpid)).encode('ascii')) tlv_port_id = lldp.PortID(subtype=lldp.PortID.SUB_PORT_COMPONENT, port_id=struct.pack(LLDPPacket.PORT_ID_STR, port_no)) tlv_ttl = lldp.TTL(ttl=ttl) tlv_end = lldp.End() tlvs = (tlv_chassis_id, tlv_port_id, tlv_ttl, tlv_end) lldp_pkt = lldp.lldp(tlvs) pkt.add_protocol(lldp_pkt) pkt.serialize() return pkt.data
def to_dict(self): return { 'dpid': dpid_to_str(self.dpid), 'port_no': port_no_to_str(self.port_no), 'hw_addr': self.hw_addr, 'name': self.name.decode('utf-8') }
def unregist_ofs(dp): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) if dp.id in QoSController._OFS_LIST: del QoSController._OFS_LIST[dp.id] QoSController._LOGGER.info('dpid=%s: Leave qos switch.', dpid_lib.dpid_to_str(dp.id))
def _topology_change_handler(self, ev): dp = ev.dp dpid_str = dpid_lib.dpid_to_str(dp.id) msg = 'Receive topology change event. Flush MAC table.' self.logger.debug("[dpid=%s] %s", dpid_str, msg) if dp.id in self.mac_to_port: self.delete_flow(dp) del self.mac_to_port[dp.id]
def get_quantum_ports(self, port_name): LOG.debug('port_name %s', port_name) command = ovs_vsctl.VSCtlCommand( 'list-ifaces-verbose', [dpid_lib.dpid_to_str(self.datapath_id), port_name]) self.run_command([command]) if command.result: return command.result[0] return None
def _do_key(dpid, key, func, ret_func): dpid = dpid_lib.str_to_dpid(dpid) try: ret = func(dpid, key) except KeyError: return Response(status=http_client.NOT_FOUND, body='no dpid/key is found %s %s' % (dpid_lib.dpid_to_str(dpid), key)) return ret_func(ret)
def _do_switch(dpid, func, ret_func): dpid = dpid_lib.str_to_dpid(dpid) try: ret = func(dpid) except KeyError: return Response(status=http_client.NOT_FOUND, body='no dpid is found %s' % dpid_lib.dpid_to_str(dpid)) return ret_func(ret)
def get_quantum_ports(self, port_name): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) LOG.debug('port_name %s', port_name) command = ovs_vsctl.VSCtlCommand( 'list-ifaces-verbose', [dpid_lib.dpid_to_str(self.datapath_id), port_name]) self.run_command([command]) if command.result: return command.result[0] return None
def _port_state_change_handler(self, ev): dpid_str = dpid_lib.dpid_to_str(ev.dp.id) of_state = { stplib.PORT_STATE_DISABLE: 'DISABLE', stplib.PORT_STATE_BLOCK: 'BLOCK', stplib.PORT_STATE_LISTEN: 'LISTEN', stplib.PORT_STATE_LEARN: 'LEARN', stplib.PORT_STATE_FORWARD: 'FORWARD' } self.logger.debug("[dpid=%s][port=%d] state=%s", dpid_str, ev.port_no, of_state[ev.port_state])
def _register_bridge(self, dp): self._unregister_bridge(dp.id) dpid_str = {'dpid': dpid_to_str(dp.id)} self.logger.info('Join as stp bridge.', extra=dpid_str) try: bridge = Bridge(dp, self.logger, self.config.get(dp.id, {}), self.send_event_to_observers) except OFPUnknownVersion as message: self.logger.error(str(message), extra=dpid_str) return self.bridge_list[dp.id] = bridge
def regist_ofs(dp, CONF): if dp.id in QoSController._OFS_LIST: return dpid_str = dpid_lib.dpid_to_str(dp.id) try: f_ofs = QoS(dp, CONF) f_ofs.set_default_flow() except OFPUnknownVersion as message: QoSController._LOGGER.info('dpid=%s: %s', dpid_str, message) return QoSController._OFS_LIST.setdefault(dp.id, f_ofs) QoSController._LOGGER.info('dpid=%s: Join qos switch.', dpid_str)
def datapath_connection_factory(socket, address): LOG.debug('connected socket:%s address:%s', socket, address) with contextlib.closing(Datapath(socket, address)) as datapath: try: datapath.serve() except: # Something went wrong. # Especially malicious switch can send malformed packet, # the parser raise exception. # Can we do anything more graceful? if datapath.id is None: dpid_str = "%s" % datapath.id else: dpid_str = dpid_to_str(datapath.id) LOG.error("Error in the datapath %s from %s", dpid_str, address) raise
def port_status_handler(self, ev): dp = ev.msg.datapath dpid_str = {'dpid': dpid_to_str(dp.id)} port = ev.msg.desc reason = ev.msg.reason link_down_flg = port.state & 0b1 if dp.id in self.bridge_list: bridge = self.bridge_list[dp.id] if reason is dp.ofproto.OFPPR_ADD: self.logger.info('[port=%d] Port add.', port.port_no, extra=dpid_str) bridge.port_add(port) elif reason is dp.ofproto.OFPPR_DELETE: self.logger.info('[port=%d] Port delete.', port.port_no, extra=dpid_str) bridge.port_delete(port) else: assert reason is dp.ofproto.OFPPR_MODIFY if bridge.ports_state[port.port_no] == port.state: # Do nothing self.logger.debug('[port=%d] Link status not changed.', port.port_no, extra=dpid_str) return if link_down_flg: self.logger.info('[port=%d] Link down.', port.port_no, extra=dpid_str) bridge.link_down(port) else: self.logger.info('[port=%d] Link up.', port.port_no, extra=dpid_str) bridge.link_up(port)
def flow_removed_handler(self, evt): """FlowRemoved event handler. when the removed flow entry was for LACP, set the status of the slave i/f to disabled, and send a event.""" msg = evt.msg datapath = msg.datapath ofproto = datapath.ofproto dpid = datapath.id match = msg.match if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: port = match.in_port dl_type = match.dl_type else: port = match['in_port'] dl_type = match['eth_type'] if ether.ETH_TYPE_SLOW != dl_type: return self.logger.info("SW=%s PORT=%d LACP exchange timeout has occurred.", dpid_to_str(dpid), port) self._set_slave_enabled(dpid, port, False) self._set_slave_timeout(dpid, port, 0) self.send_event_to_observers( EventSlaveStateChanged(datapath, port, False))
def __str__(self): return 'EventConfSwitchDelDPID<%s>' % dpid_to_str(self.dpid)
def _rest_command(*args, **kwargs): LOG.info('%s(): caller(): %s', log_utils.get_fname(1), log_utils.get_fname(2)) key, value = func(*args, **kwargs) switch_id = dpid_lib.dpid_to_str(args[0].dp.id) return {REST_SWITCHID: switch_id, key: value}
def state_change_handler(self, ev): dp = ev.datapath assert dp is not None LOG.debug(dp) if ev.state == MAIN_DISPATCHER: dp_multiple_conns = False if dp.id in self.dps: LOG.warning('Multiple connections from %s', dpid_to_str(dp.id)) dp_multiple_conns = True (self.dps[dp.id]).close() self._register(dp) switch = self._get_switch(dp.id) LOG.debug('register %s', switch) if not dp_multiple_conns: self.send_event_to_observers(event.EventSwitchEnter(switch)) else: evt = event.EventSwitchReconnected(switch) self.send_event_to_observers(evt) if not self.link_discovery: return if self.install_flow: ofproto = dp.ofproto ofproto_parser = dp.ofproto_parser # TODO:XXX need other versions if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: rule = nx_match.ClsRule() rule.set_dl_dst( addrconv.mac.text_to_bin(lldp.LLDP_MAC_NEAREST_BRIDGE)) rule.set_dl_type(ETH_TYPE_LLDP) actions = [ ofproto_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, self.LLDP_PACKET_LEN) ] dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions, priority=0xFFFF) elif ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: match = ofproto_parser.OFPMatch( eth_type=ETH_TYPE_LLDP, eth_dst=lldp.LLDP_MAC_NEAREST_BRIDGE) # OFPCML_NO_BUFFER is set so that the LLDP is not # buffered on switch parser = ofproto_parser actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] inst = [ parser.OFPInstructionActions( ofproto.OFPIT_APPLY_ACTIONS, actions) ] mod = parser.OFPFlowMod(datapath=dp, match=match, idle_timeout=0, hard_timeout=0, instructions=inst, priority=0xFFFF) dp.send_msg(mod) else: LOG.error('cannot install flow. unsupported version. %x', dp.ofproto.OFP_VERSION) # Do not add ports while dp has multiple connections to controller. if not dp_multiple_conns: for port in switch.ports: if not port.is_reserved(): self._port_added(port) self.lldp_event.set() elif ev.state == DEAD_DISPATCHER: # dp.id is None when datapath dies before handshake if dp.id is None: return switch = self._get_switch(dp.id) if switch: if switch.dp is dp: self._unregister(dp) LOG.debug('unregister %s', switch) evt = event.EventSwitchLeave(switch) self.send_event_to_observers(evt) if not self.link_discovery: return for port in switch.ports: if not port.is_reserved(): self.ports.del_port(port) self._link_down(port) self.lldp_event.set()
def list_switches(self, _req, **_kwargs): dpids = self.conf_switch.dpids() body = json.dumps([dpid_lib.dpid_to_str(dpid) for dpid in dpids]) return Response(content_type='application/json', body=body)
def to_dict(self): d = { 'dpid': dpid_to_str(self.dp.id), 'ports': [port.to_dict() for port in self.ports] } return d
def __str__(self): return 'EventConfSwitchSet<%s, %s, %s>' % ( dpid_to_str(self.dpid), self.key, self.value)
def __str__(self): return 'EventConfSwitchDel<%s, %s>' % (dpid_to_str(self.dpid), self.key)