def del_groups(self, datapath): """ Deletes all existing groups """ ofproto = datapath.ofproto parser = datapath.ofproto_parser msg = parser.OFPGroupMod(datapath, ofproto.OFPGC_DELETE, 0, ofproto.OFPG_ALL) api.send_msg(self, msg)
def _send_set_async(self, br): """Set asynchronous configuration message for the given bridge.""" datapath = br.datapath ofp = datapath.ofproto ofpp = datapath.ofproto_parser packet_in_mask = 1 << ofp.OFPR_ACTION | 1 << ofp.OFPR_INVALID_TTL port_status_mask = 1 << ofp.OFPPR_DELETE flow_removed_mask = 0 msg = ofpp.OFPSetAsync(datapath, [packet_in_mask, 0], [port_status_mask, 0], [flow_removed_mask, 0]) ryu_api.send_msg(app=self.ryuapp, msg=msg)
def del_flows(self, datapath): """ Deletes all existing flows """ ofproto = datapath.ofproto parser = datapath.ofproto_parser msg = parser.OFPFlowMod(datapath=datapath, table_id=ofproto.OFPTT_ALL, command=ofproto.OFPFC_DELETE, out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY) api.send_msg(self, msg)
def _send_arp_reply(self, datapath, port, pkt): ofp = datapath.ofproto ofpp = datapath.ofproto_parser pkt.serialize() data = pkt.data actions = [ofpp.OFPActionOutput(port=port)] out = ofpp.OFPPacketOut(datapath=datapath, buffer_id=ofp.OFP_NO_BUFFER, in_port=ofp.OFPP_CONTROLLER, actions=actions, data=data) ryu_api.send_msg(self.ryuapp, out)
def _send_unknown_packet(self, msg, in_port, out_port): datapath = msg.datapath ofp = datapath.ofproto ofpp = datapath.ofproto_parser data = None if msg.buffer_id == ofp.OFP_NO_BUFFER: data = msg.data actions = [ofpp.OFPActionOutput(port=out_port)] out = ofpp.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions, data=data) ryu_api.send_msg(self.ryuapp, out)
def _add_flow_to_avoid_unknown_packet(self, datapath, match): LOG.debug("add flow to avoid an unknown packet from packet-in") ofp = datapath.ofproto ofpp = datapath.ofproto_parser instructions = [ofpp.OFPInstructionGotoTable( table_id=constants.FLOOD_TO_TUN)] out = ofpp.OFPFlowMod(datapath, table_id=constants.PATCH_LV_TO_TUN, command=ofp.OFPFC_ADD, idle_timeout=5, priority=20, match=match, instructions=instructions) ryu_api.send_msg(self.ryuapp, out)
def _add_flow_to_avoid_unknown_packet(self, datapath, match): LOG.debug("add flow to avoid an unknown packet from packet-in") ofp = datapath.ofproto ofpp = datapath.ofproto_parser instructions = [ ofpp.OFPInstructionGotoTable(table_id=constants.FLOOD_TO_TUN) ] out = ofpp.OFPFlowMod(datapath, table_id=constants.PATCH_LV_TO_TUN, command=ofp.OFPFC_ADD, idle_timeout=5, priority=20, match=match, instructions=instructions) ryu_api.send_msg(self.ryuapp, out)
def get_stats(self, cookie: int = 0, cookie_mask: int = 0): """ Use Ryu API to send a stats request containing cookie and cookie mask, retrieve a response and convert to a Rule Record Table """ parser = self._datapath.ofproto_parser message = parser.OFPFlowStatsRequest(datapath=self._datapath, cookie=cookie, cookie_mask=cookie_mask) try: response = ofctl_api.send_msg(self, message, reply_cls=parser.OFPFlowStatsReply, reply_multi=False) if response == None: self.logger.error( "No rule records match the specified cookie and cookie mask" ) return RuleRecordTable() else: usage = self._get_usage_from_flow_stat(response.body) record_table = RuleRecordTable(records=usage.values(), epoch=global_epoch) return record_table except (InvalidDatapath, OFError, UnexpectedMultiReply): self.logger.error( "Could not obtain rule records due to either InvalidDatapath, OFError or UnexpectedMultiReply" ) return RuleRecordTable()
def get_flows(self, datapath=None, table_id=None, timeout=None): if datapath is None: datapath = self.datapath if table_id is None: table_id = datapath.ofproto.OFPTT_ALL if not timeout: timeout = DEFAULT_GET_FLOWS_TIMEOUT parser = datapath.ofproto_parser msg = parser.OFPFlowStatsRequest(datapath, table_id=table_id) try: with eventlet.timeout.Timeout(seconds=timeout): replies = ofctl_api.send_msg( self.api, msg, reply_cls=parser.OFPFlowStatsReply, reply_multi=True) except BaseException: LOG.exception("Failed to get flows") return [] if replies is None: LOG.error("No reply for get flows") return [] flows = [body for reply in replies for body in reply.body] LOG.debug("Got the following flows: %s", flows) return flows
def _send_msg(self, msg, reply_cls=None, reply_multi=False): timeout_sec = cfg.CONF.OVS.of_request_timeout timeout = eventlet.Timeout(seconds=timeout_sec) try: result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi) except ryu_exc.RyuException as e: m = _("ofctl request %(request)s error %(error)s") % { "request": msg, "error": e, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) except eventlet.Timeout as e: with excutils.save_and_reraise_exception() as ctx: if e is timeout: ctx.reraise = False m = _("ofctl request %(request)s timed out") % { "request": msg, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) finally: timeout.cancel() LOG.debug("ofctl request %(request)s result %(result)s", { "request": msg, "result": result }) return result
def switch_features_handler(self, ev): datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser # Tell the Switch to send the complete packet with packet_in messages req = parser.OFPSetConfig(datapath, ofproto.OFPC_FRAG_NORMAL, 2000) datapath.send_msg(req) # Request the Switch Configuration req = parser.OFPGetConfigRequest(datapath) datapath.send_msg(req) msg = parser.OFPPortDescStatsRequest(datapath=datapath) result = api.send_msg(self, msg, reply_cls=parser.OFPPortDescStatsReply, reply_multi=True) if len(result) > 0: hub.spawn(self._init_topology, result[0].body) hub.spawn(self.create_rules_monitor_dhcp, datapath) #print(result) # install table-miss flow entry # We specify NO BUFFER to max_len of the output action due to # OVS bug. At this moment, if we specify a lesser number, e.g., # 128, OVS will send Packet-In with invalid buffer_id and # truncated packet data. In that case, we cannot output packets # correctly. The bug has been fixed in OVS v2.1.0. match = parser.OFPMatch() actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] self.add_flow(datapath, 0, match, actions)
def aggregate_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPAggregateStatsRequest(datapath) for msg in api.send_msg(self.app, req, reply_cls=p.OFPStatsReply, reply_multi=True): self.send(msg.body, req, tm)
def _send_msg(self, msg, reply_cls=None, reply_multi=False, active_bundle=None): timeout_sec = cfg.CONF.OVS.of_request_timeout timeout = eventlet.Timeout(seconds=timeout_sec) if active_bundle is not None: (dp, ofp, ofpp) = self._get_dp() msg = ofpp.ONFBundleAddMsg(dp, active_bundle['id'], active_bundle['bundle_flags'], msg, []) try: result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi) except ryu_exc.RyuException as e: m = _("ofctl request %(request)s error %(error)s") % { "request": msg, "error": e, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) except eventlet.Timeout as e: with excutils.save_and_reraise_exception() as ctx: if e is timeout: ctx.reraise = False m = _("ofctl request %(request)s timed out") % { "request": msg, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) finally: timeout.cancel() LOG.debug("ofctl request %(request)s result %(result)s", {"request": msg, "result": result}) return result
def _send_msg(self, msg, reply_cls=None, reply_multi=False): timeout_sec = cfg.CONF.OVS.of_request_timeout timeout = eventlet.timeout.Timeout(seconds=timeout_sec) try: result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi) except ryu_exc.RyuException as e: m = _LE("ofctl request %(request)s error %(error)s") % { "request": msg, "error": e, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) except eventlet.timeout.Timeout as e: with excutils.save_and_reraise_exception() as ctx: if e is timeout: ctx.reraise = False m = _LE("ofctl request %(request)s timed out") % { "request": msg, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) finally: timeout.cancel() LOG.debug("ofctl request %(request)s result %(result)s", {"request": msg, "result": result}) return result
def _send_msg(self, msg, reply_cls=None, reply_multi=False, active_bundle=None): timeout_sec = constants.OF_REQUEST_TIMEOUT timeout = eventlet.Timeout(seconds=timeout_sec) if active_bundle is not None: (dp, ofp, ofpp) = self._get_dp() msg = ofpp.ONFBundleAddMsg(dp, active_bundle['id'], active_bundle['bundle_flags'], msg, []) try: result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi) except ryu_exc.RyuException as e: m = _("ofctl request %(request)s error %(error)s") % { "request": msg, "error": e, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) except eventlet.Timeout as e: with excutils.save_and_reraise_exception() as ctx: if e is timeout: ctx.reraise = False m = "ofctl request %(request)s timed out" % { "request": msg, } LOG.error(m) # NOTE(yamamoto): use RuntimeError for compat with ovs_lib raise RuntimeError(m) finally: timeout.cancel() LOG.debug("ofctl request %(request)s result %(result)s", {"request": msg, "result": result}) return result
def port_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPPortStatsRequest(datapath, flags=0, port_no=datapath.ofproto.OFPP_ANY) for msg in api.send_msg(self.app, req, reply_cls=p.OFPPortStatsReply, reply_multi=True): for b in msg.body: self.send(b, req, tm)
def _send_unknown_packet(self, msg, in_port, out_port): LOG.debug("unknown packet-out in-port %(in_port)s " "out-port %(out_port)s msg %(msg)s", {'in_port': in_port, 'out_port': out_port, 'msg': msg}) datapath = msg.datapath ofp = datapath.ofproto ofpp = datapath.ofproto_parser data = None if msg.buffer_id == ofp.OFP_NO_BUFFER: data = msg.data actions = [ofpp.OFPActionOutput(port=out_port)] out = ofpp.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions, data=data) ryu_api.send_msg(self.ryuapp, out)
def flow_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPFlowStatsRequest(datapath) for msg in api.send_msg(self.app, req, reply_cls=p.OFPFlowStatsReply, reply_multi=True): for b in msg.body: self.send(b, req, tm)
def _get_ports(self, br): """Generate ports.Port instances for the given bridge.""" datapath = br.datapath ofpp = datapath.ofproto_parser msg = ofpp.OFPPortDescStatsRequest(datapath=datapath) descs = ryu_api.send_msg(app=self.ryuapp, msg=msg, reply_cls=ofpp.OFPPortDescStatsReply, reply_multi=True) for d in descs: for p in d.body: yield ports.Port.from_ofp_port(p)
def queue_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPQueueStatsRequest(datapath, 0, datapath.ofproto.OFPP_ALL, datapath.ofproto.OFPQ_ALL) for msg in api.send_msg(self.app, req, reply_cls=p.OFPQueueStatsReply, reply_multi=True): for b in msg.body: self.send(b, req, tm)
def aggregate_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPAggregateStatsRequest(datapath, 0, datapath.ofproto_parser.OFPMatch(), 0xff, datapath.ofproto.OFPP_NONE) for msg in api.send_msg(self.app, req, reply_cls=p.OFPAggregateStatsReply, reply_multi=True): for body in msg.body: self.send(body, req, tm)
def aggregate_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPAggregateStatsRequest(datapath, 0, datapath.ofproto.OFPTT_ALL, datapath.ofproto.OFPP_ANY, datapath.ofproto.OFPG_ANY, 0, 0, datapath.ofproto_parser.OFPMatch()) for msg in api.send_msg(self.app, req, reply_cls=p.OFPAggregateStatsReply, reply_multi=True): self.send(msg.body, req, tm)
def port_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPPortStatsRequest(datapath, 0, datapath.ofproto.OFPP_NONE) for msg in api.send_msg(self.app, req, reply_cls=p.OFPPortStatsReply, reply_multi=True): for b in msg.body: self.send(b, req, tm)
def group_stats(self): datapath = self.datapath p = datapath.ofproto_parser tm = time.time() req = p.OFPGroupStatsRequest(datapath) for msg in api.send_msg(self.app, req, reply_cls=p.OFPStatsReply, reply_multi=True): for b in msg.body: self.send(b, req, tm)
def send_msg(app, datapath, buf): ''' send a binary openflow message @return same as ryu.app.ofctl.api.send_msg useful with ofpstr, for example class X(ryu.base.app_manager.RyuApp): @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def on_switch_ready(self, ev): rule="in_port=1,@apply,output=2" send_bin(self, ev.msg.datapath, ofpstr.ofp4.str2mod(rule)) ''' msg_cls = dict() stats_cls = dict() for name in dir(datapath.ofproto_parser): t = getattr(datapath.ofproto_parser, name) if type(t) == type and issubclass(t, MsgBase) and hasattr( t, "cls_msg_type"): if hasattr(t, "cls_stats_type"): stats_cls[name] = t else: msg_cls[name] = t phdr = struct.unpack_from("!BBHI", buf) reply_cls = None reply_multi = False for cls in stats_cls.values(): if phdr[1] == cls.cls_msg_type: reply_multi = True break if reply_multi: stats_type = struct.unpack_from("!H", pmsg, 8)[0] for cls in stats_cls.values(): if cls.cls_stats_type != stats_type: continue if cls.cls_msg_type == phdr[1]: continue reply_cls = cls break else: for name, req in msg_cls.items(): if req.cls_msg_type == phdr[1]: rname = api_expect.get(name) if rname: reply_cls = msg_cls[rname] return api.send_msg(app, RawMsg(datapath, buf), reply_cls=reply_cls, reply_multi=reply_multi)
def _send_unknown_packet(self, msg, in_port, out_port): LOG.debug( "unknown packet-out in-port %(in_port)s " "out-port %(out_port)s msg %(msg)s", { 'in_port': in_port, 'out_port': out_port, 'msg': msg }) datapath = msg.datapath ofp = datapath.ofproto ofpp = datapath.ofproto_parser data = None if msg.buffer_id == ofp.OFP_NO_BUFFER: data = msg.data actions = [ofpp.OFPActionOutput(port=out_port)] out = ofpp.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id, in_port=in_port, actions=actions, data=data) ryu_api.send_msg(self.ryuapp, out)
def send_msg(app, datapath, buf): ''' send a binary openflow message @return same as ryu.app.ofctl.api.send_msg useful with ofpstr, for example class X(ryu.base.app_manager.RyuApp): @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def on_switch_ready(self, ev): rule="in_port=1,@apply,output=2" send_bin(self, ev.msg.datapath, ofpstr.ofp4.str2mod(rule)) ''' msg_cls = dict() stats_cls = dict() for name in dir(datapath.ofproto_parser): t = getattr(datapath.ofproto_parser, name) if type(t)==type and issubclass(t, MsgBase) and hasattr(t, "cls_msg_type"): if hasattr(t, "cls_stats_type"): stats_cls[name] = t else: msg_cls[name] = t phdr = struct.unpack_from("!BBHI", buf) reply_cls = None reply_multi = False for cls in stats_cls.values(): if phdr[1] == cls.cls_msg_type: reply_multi = True break if reply_multi: stats_type = struct.unpack_from("!H", pmsg, 8)[0] for cls in stats_cls.values(): if cls.cls_stats_type != stats_type: continue if cls.cls_msg_type == phdr[1]: continue reply_cls = cls break else: for name, req in msg_cls.items(): if req.cls_msg_type == phdr[1]: rname = api_expect.get(name) if rname: reply_cls = msg_cls[rname] return api.send_msg(app, RawMsg(datapath, buf), reply_cls=reply_cls, reply_multi=reply_multi)
def get_stats(self, cookie: int = 0, cookie_mask: int = 0): """ Use Ryu API to send a stats request containing cookie and cookie mask, retrieve a response and convert to a Rule Record Table and remove old flows """ if not self._datapath: self.logger.error( "Could not initialize datapath for stats retrieval") return RuleRecordTable() parser = self._datapath.ofproto_parser message = parser.OFPFlowStatsRequest( datapath=self._datapath, table_id=self.tbl_num, cookie=cookie, cookie_mask=cookie_mask, ) try: response = ofctl_api.send_msg( self, message, reply_cls=parser.OFPFlowStatsReply, reply_multi=True, ) if not response: self.logger.error( "No rule records match the specified cookie and cookie mask" ) return RuleRecordTable() aggregated_msgs = [] for r in response: aggregated_msgs += r.body usage = self._get_usage_from_flow_stat(aggregated_msgs) self.loop.call_soon_threadsafe(self._delete_old_flows, usage.values()) record_table = RuleRecordTable( records=usage.values(), epoch=global_epoch, ) return record_table except (InvalidDatapath, OFError, UnexpectedMultiReply): self.logger.error( "Could not obtain rule records due to either InvalidDatapath, OFError or UnexpectedMultiReply" ) return RuleRecordTable()
def _send_msg(self, msg, reply_cls=None, reply_multi=False): timeout_sec = 20 # TODO(heshan) should be configured in cfg file timeout = eventlet.timeout.Timeout(seconds=timeout_sec) result = None try: result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi) except ryu_exc.RyuException as e: m = _LE("ofctl request %(request)s error %(error)s") % { "request": msg, "error": e, } LOG.error(_LE("exception occurred, %s"), m) except eventlet.timeout.Timeout as e: LOG.error(_LE("exception occurred, %s"), e) finally: timeout.cancel() LOG.debug("ofctl request %(request)s result %(result)s", {"request": msg, "result": result}) return result
def _send_msg(self, msg, reply_cls=None, reply_multi=False): timeout_sec = 20 # TODO(heshan) should be configured in cfg file timeout = eventlet.timeout.Timeout(seconds=timeout_sec) result = None try: result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi) except ryu_exc.RyuException as e: m = _LE("ofctl request %(request)s error %(error)s") % { "request": msg, "error": e, } LOG.error(_LE("exception occurred, %s"), m) except eventlet.timeout.Timeout as e: LOG.error(_LE("exception occurred, %s"), e) finally: timeout.cancel() LOG.debug("ofctl request %(request)s result %(result)s", { "request": msg, "result": result }) return result
def _send_msg(self, msg): return ofctl_api.send_msg(self._app, msg)
def handle_datapath(self, ev): if not ev.enter or self.done: print('Skipping') return self.done = True dp = ev.dp parser = dp.ofproto_parser print('Switch connected') print('Collecting') # Request switch features XXX TODO FAILING try: msg = parser.OFPFeaturesRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPSwitchFeatures) self.collection['switch_features'] = res.to_json() if res else res print('Switch Features') except Exception as e: print("Exception collecting Switch Features") print(e) # Request config - non multipart try: msg = parser.OFPGetConfigRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPGetConfigReply) self.collection['config'] = ({ "flags": res.flags, "miss_send_len": res.miss_send_len } if res else res) print('Switch Config') except Exception as e: print("Exception collecting Switch Config") print(e) # Request switch description - multipart single item try: msg = parser.OFPDescStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPDescStatsReply, reply_multi=True) if len(res) != 1: raise Exception(('Expecting only a single response from' ' switch description', res)) self.collection['desc'] = res[0].body print('Switch Description') except Exception as e: print("Exception collecting Switch Descripton") print(e) # Request all stats from all tables - multipart list try: msg = parser.OFPFlowStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPFlowStatsReply, reply_multi=True) l = [stat for stats in res for stat in stats.body] self.collection['flow_stats'] = l print('Flows Stats') except Exception as e: print("Exception collecting Flow Stats") print(e) # Request table stats - multipart list try: msg = parser.OFPTableStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPTableStatsReply, reply_multi=True) l = [table for tables in res for table in tables.body] self.collection['table_stats'] = l print('Table Stats') except Exception as e: print("Exception collecting Table Stats") print(e) # Request port stats - multipart list try: msg = parser.OFPPortStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPPortStatsReply, reply_multi=True) l = [port for ports in res for port in ports.body] self.collection['port_stats'] = l print('Port Stats') except Exception as e: print("Exception collecting Port Stats") print(e) # Request port descriptions - multipart list try: msg = parser.OFPPortDescStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPPortDescStatsReply, reply_multi=True) l = [port for ports in res for port in ports.body] self.collection['port_desc'] = l print('Port Description') except Exception as e: print("Exception collecting Port Description") print(e) # Request queue stats - mulitpart list try: msg = parser.OFPQueueStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPQueueStatsReply, reply_multi=True) l = [queue for queues in res for queue in queues.body] self.collection['queue_stats'] = l print('Queue Stats') except Exception as e: print("Exception collecting Queue Stats") print(e) # Request group stats - multipart list try: msg = parser.OFPGroupStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPGroupStatsReply, reply_multi=True) l = [group for groups in res for group in groups.body] self.collection['group_stats'] = l print('Group Stats') except Exception as e: print("Exception collecting Group Stats") print(e) # Request group desc - multipart list try: msg = parser.OFPGroupDescStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPGroupDescStatsReply, reply_multi=True) l = [group for groups in res for group in groups.body] self.collection['group_desc'] = l print('Group Description') except Exception as e: print("Exception collecting Group Description") print(e) # Request group features - multipart single item try: msg = parser.OFPGroupFeaturesStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPGroupFeaturesStatsReply, reply_multi=True) if len(res) != 1: raise Exception(('Expecting only a single response from' ' group features', res)) self.collection['group_features'] = res[0].body print('Group Features') except Exception as e: print("Exception collecting Group Features") print(e) # Request meter stats - multipart list try: msg = parser.OFPMeterStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPMeterStatsReply, reply_multi=True) l = [meter for meters in res for meter in meters.body] self.collection['meter_stats'] = l print('Meter Stats') except Exception as e: print("Exception collecting Meter Stats") print(e) # Request meter config - multipart list try: msg = parser.OFPMeterConfigStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPMeterConfigStatsReply, reply_multi=True) l = [meter for meters in res for meter in meters.body] self.collection['meter_config'] = l print('Meter Config') except Exception as e: print("Exception collecting Meter Config") print(e) # Request meter features - single item try: msg = parser.OFPMeterFeaturesStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPMeterFeaturesStatsReply, reply_multi=True) if len(res) != 1: raise Exception(('Expecting only a single response from' ' meter features', res)) self.collection['meter_features'] = res[0].body print('Meter Features') except Exception as e: print("Exception collecting Meter Features") print(e) # Request table features, this can be very large try: msg = parser.OFPTableFeaturesStatsRequest(dp) res = api.send_msg(self, msg, reply_cls=parser.OFPTableFeaturesStatsReply, reply_multi=True) l = [table for tables in res for table in tables.body] self.collection['table_features'] = l print('Table Features') except Exception as e: print("Exception collecting Table Features") print(e) # Request queue config (this is done on a per port basis) so # querying all does not work so well. # Not multipart!? try: msg = parser.OFPQueueGetConfigRequest(dp, ofproto_v1_3.OFPP_ANY) res = api.send_msg(self, msg, reply_cls=parser.OFPQueueGetConfigReply) self.collection['queue_config'] = res.queues if res else res print('Queue Config') except Exception as e: print("Exception collecting Queue Config") print(e) pickle.dump(self.collection, open("switch_state.pickle", "wb")) print('Switch dumped successfully')
def switch_features_handler(self, ev): datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser dpid = datapath.id topo_node = self.topology.nodes.get(dpid) if topo_node is None: self.logger.error( f"Received information about unknown switch id={dpid}") return self.logger.info(f"Received information about switch id={dpid}") if isinstance(topo_node, topo.Router): self.logger.info(f"Switch {dpid} is a chirouter-managed router") self.router_dpids.add(dpid) # Request information about the router's ports msg = parser.OFPPortDescStatsRequest(datapath=datapath) result = ofctl_api.send_msg(self, msg, reply_cls=parser.OFPPortDescStatsReply, reply_multi=True) for reply in result: for port in reply.body: port_name = port.name.decode('UTF-8') if not "-" in port_name: continue node_name, iface_name = port_name.split("-") if iface_name in topo_node.interfaces: self.logger.info(f"Processing port {port_name}") iface = topo_node.interfaces[iface_name] self.of2topo[(dpid, port.port_no)] = iface self.topo2of[iface] = (dpid, port.port_no) iface.hwaddr = str(port.hw_addr) if len(self.router_dpids) == self.topology.num_routers: self.logger.info( "All routers accounted for. Connecting to chirouter...") self.client.connect() message_thread = threading.Thread(target=self.process_messages) message_thread.daemon = True message_thread.start() elif isinstance(topo_node, topo.Switch): self.logger.info(f"Switch {dpid} is a regular switch") self.switch_dpids.add(dpid) print() # Install table-miss flow entry (so frames are sent to # the controller for processing) match = parser.OFPMatch() actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] self.add_flow(datapath, 0, match, actions)
def rhandle(self, dpid, sock): datapath = self.dpset.get(dpid) msg_cls = dict() stats_cls = dict() for name in dir(datapath.ofproto_parser): t = getattr(datapath.ofproto_parser, name) if type(t) == type and issubclass(t, MsgBase) and hasattr( t, "cls_msg_type"): if hasattr(t, "cls_stats_type"): stats_cls[name] = t else: msg_cls[name] = t barrier = msg_cls.get("OFPBarrierRequest") xid = 0 sock.send(struct.pack("!BBHI", datapath.ofproto.OFP_VERSION, 0, 8, 1)) while self.accepting_sockets[dpid]: pmsg = sock.recv(8) if not pmsg: break phdr = struct.unpack("!BBHI", pmsg) if phdr[2] > 8: pmsg = pmsg + sock.recv(phdr[2] - 8) if phdr[1] == 0: continue # skip hello if barrier and barrier.cls_msg_type == phdr[1]: # api wants to handle barrier rmsg = struct.pack("!BBHI", phdr[0], msg_cls["OFPBarrierReply"].cls_msg_type, 8, phdr[3]) sock.send(rmsg) continue reply_cls = None reply_multi = False for cls in stats_cls.values(): if phdr[1] == cls.cls_msg_type: reply_multi = True break if reply_multi: stats_type = struct.unpack_from("!H", pmsg, 8)[0] for cls in stats_cls.values(): if cls.cls_stats_type != stats_type: continue if cls.cls_msg_type == phdr[1]: continue reply_cls = cls break else: for name, req in msg_cls.items(): if req.cls_msg_type == phdr[1]: rname = api_expect.get(name) if rname: reply_cls = msg_cls[rname] rmsgs = api.send_msg(self, RawMsg(self.dpset.get(dpid), pmsg), reply_cls=reply_cls, reply_multi=reply_multi) if reply_multi: for r in rmsgs: h = struct.unpack_from("!BBHI", r.buf) sock.send( struct.pack("!BBHI", h[0], h[1], h[2], phdr[3]) + r.buf[8:]) elif rmsgs: h = struct.unpack_from("!BBHI", rmsgs.buf) sock.send( struct.pack("!BBHI", h[0], h[1], h[2], phdr[3]) + rmsgs.buf[8:]) sock.close()
def rhandle(self, dpid, sock): datapath = self.dpset.get(dpid) msg_cls = dict() stats_cls = dict() for name in dir(datapath.ofproto_parser): t = getattr(datapath.ofproto_parser, name) if type(t)==type and issubclass(t, MsgBase) and hasattr(t, "cls_msg_type"): if hasattr(t, "cls_stats_type"): stats_cls[name] = t else: msg_cls[name] = t barrier = msg_cls.get("OFPBarrierRequest") xid = 0 sock.send(struct.pack("!BBHI", datapath.ofproto.OFP_VERSION, 0, 8, 1)) while self.accepting_sockets[dpid]: pmsg = sock.recv(8) if not pmsg: break phdr = struct.unpack("!BBHI", pmsg) if phdr[2] > 8: pmsg = pmsg + sock.recv(phdr[2]-8) if phdr[1] == 0: continue # skip hello if barrier and barrier.cls_msg_type==phdr[1]: # api wants to handle barrier rmsg = struct.pack("!BBHI", phdr[0], msg_cls["OFPBarrierReply"].cls_msg_type, 8, phdr[3]) sock.send(rmsg) continue reply_cls = None reply_multi = False for cls in stats_cls.values(): if phdr[1] == cls.cls_msg_type: reply_multi = True break if reply_multi: stats_type = struct.unpack_from("!H", pmsg, 8)[0] for cls in stats_cls.values(): if cls.cls_stats_type != stats_type: continue if cls.cls_msg_type == phdr[1]: continue reply_cls = cls break else: for name, req in msg_cls.items(): if req.cls_msg_type == phdr[1]: rname = api_expect.get(name) if rname: reply_cls = msg_cls[rname] rmsgs = api.send_msg(self, RawMsg(self.dpset.get(dpid), pmsg), reply_cls=reply_cls, reply_multi=reply_multi) if reply_multi: for r in rmsgs: h = struct.unpack_from("!BBHI", r.buf) sock.send(struct.pack("!BBHI", h[0], h[1], h[2], phdr[3])+r.buf[8:]) elif rmsgs: h = struct.unpack_from("!BBHI", rmsgs.buf) sock.send(struct.pack("!BBHI", h[0], h[1], h[2], phdr[3])+rmsgs.buf[8:]) sock.close()