Do you have any reason prefixing double underscore "__" instead of single underscore "_"?
thanks On Fri, Feb 22, 2013 at 07:14:20PM +0900, YAMADA Hideki wrote: > This is an alternative of dpset, which supports event passing. > > event.py: event class > switch.py: switch(datapath) discovery app using ofp_event > dumper.py: test and example app using switch discovery event > > TODO: support link discovery using LLDP. > > Signed-off-by: YAMADA Hideki <[email protected]> > --- > ryu/physicaltopology/dumper.py | 87 ++++++++++++++++ > ryu/physicaltopology/event.py | 85 ++++++++++++++++ > ryu/physicaltopology/switch.py | 207 > ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 379 insertions(+), 0 deletions(-) > create mode 100644 ryu/physicaltopology/__init__.py > create mode 100644 ryu/physicaltopology/dumper.py > create mode 100644 ryu/physicaltopology/event.py > create mode 100644 ryu/physicaltopology/switch.py > > diff --git a/ryu/physicaltopology/__init__.py > b/ryu/physicaltopology/__init__.py > new file mode 100644 > index 0000000..e69de29 > diff --git a/ryu/physicaltopology/dumper.py b/ryu/physicaltopology/dumper.py > new file mode 100644 > index 0000000..ada890a > --- /dev/null > +++ b/ryu/physicaltopology/dumper.py > @@ -0,0 +1,87 @@ > +# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. > +# > +# Licensed under the Apache License, Version 2.0 (the "License"); > +# you may not use this file except in compliance with the License. > +# You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, > +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > +# implied. > +# See the License for the specific language governing permissions and > +# limitations under the License. > + > + > +import logging > +import gevent > +import gevent.queue > + > +from ryu.base import app_manager > +from ryu.controller import handler > + > +from .event import EventSwitchEnter, EventSwitchLeave > +from .event import EventPortAdd, EventPortDelete, EventPortModify > +from .event import EventSwitchListRequest, EventSwitchListReply > +import switch > + > +LOG = logging.getLogger(__name__) > + > + > +class DiscoveryEventDumper(app_manager.RyuApp): > + ''' This app dumps discovery events > + ''' > + > + # For testing when multi request threads, there is no race condition > + __THREAD_COUNT = 2 > + __THREAD_SLEEP = 5 > + > + def __init__(self): > + super(DiscoveryEventDumper, self).__init__() > + > + for i in range(0, self.__THREAD_COUNT): > + self.threads.append(gevent.spawn_later(0, self.__request_loop)) > + > + self.is_active = True > + > + @handler.set_ev_cls(EventSwitchEnter) > + def dp_enter_handler(self, ev): > + LOG.debug(ev) > + > + @handler.set_ev_cls(EventSwitchLeave) > + def dp_leave_handler(self, ev): > + LOG.debug(ev) > + > + @handler.set_ev_cls(EventPortAdd) > + def dp_port_add_handler(self, ev): > + LOG.debug(ev) > + > + @handler.set_ev_cls(EventPortDelete) > + def dp_port_delete_handler(self, ev): > + LOG.debug(ev) > + > + @handler.set_ev_cls(EventPortModify) > + def dp_port_modify_handler(self, ev): > + LOG.debug(ev) > + > + def __get_switches(self, dpid=None): > + request = EventSwitchListRequest(dpid) > + self.send_request(switch.SwitchDiscovery.__name__, request) > + > + reply = self.recv_reply(request.xid) > + assert reply.xid == request.xid > + > + return reply.switches > + > + def __request_loop(self): > + while self.is_active: > + all_switches = self.__get_switches() > + if len(all_switches) > 0: > + LOG.debug('request thread(%s) print ALL Switches: ', > + id(gevent.getcurrent())) > + for sw in all_switches: > + LOG.debug(' %s', sw) > + #sw1 = self.__get_switches(1) > + #LOG.debug('SW1: %s', sw1) > + gevent.sleep(self.__THREAD_SLEEP) > diff --git a/ryu/physicaltopology/event.py b/ryu/physicaltopology/event.py > new file mode 100644 > index 0000000..34fa863 > --- /dev/null > +++ b/ryu/physicaltopology/event.py > @@ -0,0 +1,85 @@ > +# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. > +# > +# Licensed under the Apache License, Version 2.0 (the "License"); > +# you may not use this file except in compliance with the License. > +# You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, > +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > +# implied. > +# See the License for the specific language governing permissions and > +# limitations under the License. > + > +import logging > +from ryu.controller import event > + > +LOG = logging.getLogger(__name__) > + > + > +class EventSwitchBase(event.EventBase): > + def __init__(self, switch): > + super(EventSwitchBase, self).__init__() > + self.switch = switch > + > + def __str__(self): > + return '%s<dpid=%s, %s ports>' % \ > + (self.__class__.__name__, > + self.switch.dpid, len(self.switch.ports)) > + > + > +class EventSwitchEnter(EventSwitchBase): > + def __init__(self, switch): > + super(EventSwitchEnter, self).__init__(switch) > + > + > +class EventSwitchLeave(EventSwitchBase): > + def __init__(self, switch): > + super(EventSwitchLeave, self).__init__(switch) > + > + > +class EventPortBase(event.EventBase): > + def __init__(self, port): > + super(EventPortBase, self).__init__() > + self.port = port > + > + def __str__(self): > + return '%s<%s>' % (self.__class__.__name__, self.port) > + > + > +class EventPortAdd(EventPortBase): > + def __init__(self, port): > + super(EventPortAdd, self).__init__(port) > + > + > +class EventPortDelete(EventPortBase): > + def __init__(self, port): > + super(EventPortDelete, self).__init__(port) > + > + > +class EventPortModify(EventPortBase): > + def __init__(self, port): > + super(EventPortModify, self).__init__(port) > + > + > +class EventSwitchListRequest(event.EventRequestBase): > + # If dpid is None, reply all list > + def __init__(self, dpid=None): > + super(EventSwitchListRequest, self).__init__() > + self.dpid = dpid > + > + def __str__(self): > + return 'EventSwitchListRequest<src=%s, xid=%s, dpid=%s>' % \ > + (self.src, self.xid, self.dpid) > + > + > +class EventSwitchListReply(event.EventReplyBase): > + def __init__(self, switches): > + super(EventSwitchListReply, self).__init__() > + self.switches = switches > + > + def __str__(self): > + return 'EventSwitchListReply<src=%s, xid=%s, %s>' % \ > + (self.src, self.xid, self.switches) > diff --git a/ryu/physicaltopology/switch.py b/ryu/physicaltopology/switch.py > new file mode 100644 > index 0000000..9f99ead > --- /dev/null > +++ b/ryu/physicaltopology/switch.py > @@ -0,0 +1,207 @@ > +# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. > +# > +# Licensed under the Apache License, Version 2.0 (the "License"); > +# you may not use this file except in compliance with the License. > +# You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, > +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or > +# implied. > +# See the License for the specific language governing permissions and > +# limitations under the License. > + > +import logging > +from ryu.base import app_manager > +from ryu.controller import ofp_event, handler > + > +from .event import EventSwitchEnter, EventSwitchLeave > +from .event import EventPortAdd, EventPortDelete, EventPortModify > +from .event import EventSwitchListRequest, EventSwitchListReply > +LOG = logging.getLogger(__name__) > + > + > +class Port(object): > + # This is data class passed by EventPortXXX > + def __init__(self, dpid, ofproto, ofpport): > + super(Port, self).__init__() > + > + self.dpid = dpid > + self.__ofproto = ofproto > + > + self.__config = ofpport.config > + self.__state = ofpport.state > + self.port_no = ofpport.port_no > + self.hw_addr = ofpport.hw_addr > + self.name = ofpport.name > + > + def is_reserved(self): > + return self.port_no > self.__ofproto.OFPP_MAX > + > + def is_down(self): > + return (self.__state & self.__ofproto.OFPPS_LINK_DOWN) > 0 \ > + or (self.__config & self.__ofproto.OFPPC_PORT_DOWN) > 0 > + > + def is_live(self): > + # NOTE: OF1.2 has OFPPS_LIVE state > + # return (self.__state & self.__ofproto.OFPPS_LIVE) > 0 > + return not self.is_down() > + > + # for Switch.del_port() > + def __eq__(self, other): > + return self.dpid == other.dpid and self.port_no == other.port_no > + > + def __ne__(self, other): > + return not self.__eq__(other) > + > + def __hash__(self): > + return hash((self.dpid, self.port_no)) > + > + def __str__(self): > + LIVE_MSG = {False: 'DOWN', True: 'LIVE'} > + return 'Port<dpid=%s, port_no=%s, %s>' % \ > + (self.dpid, self.port_no, LIVE_MSG[self.is_live()]) > + > + > +class Switch(object): > + # This is data class passed by EventSwitchXXX > + def __init__(self, dp): > + super(Switch, self).__init__() > + > + self.__ofproto = dp.ofproto > + self.dpid = dp.id > + self.ports = [] > + > + def add_port(self, ofpport): > + port = Port(self.dpid, self.__ofproto, ofpport) > + if not port.is_reserved(): > + self.ports.append(port) > + > + def del_port(self, ofpport): > + self.ports.remove(Port(ofpport)) > + > + def __str__(self): > + msg = 'Switch<dpid=%s, ' % self.dpid > + for port in self.ports: > + msg += str(port) + ' ' > + > + msg += '>' > + return msg > + > + > +class PortState(dict): > + # dict: int port_no -> OFPPort port > + # OFPPort is defined in ryu.ofproto.ofproto_v1_X_parser > + def __init__(self): > + super(PortState, self).__init__() > + > + def add(self, port_no, port): > + self[port_no] = port > + > + def remove(self, port_no): > + del self[port_no] > + > + def modify(self, port_no, port): > + self[port_no] = port > + > + > +class SwitchDiscovery(app_manager.RyuApp): > + _EVENTS = [EventSwitchEnter, EventSwitchLeave, > + EventPortAdd, EventPortDelete, EventPortModify] > + > + def __init__(self): > + super(SwitchDiscovery, self).__init__() > + > + self.dps = {} # datapath_id => class Datapath > + self.port_state = {} # datapath_id => ports > + > + def __register(self, dp): > + assert dp.id is not None > + assert dp.id not in self.dps > + > + self.dps[dp.id] = dp > + self.port_state[dp.id] = PortState() > + for port in dp.ports.values(): > + self.port_state[dp.id].add(port.port_no, port) > + > + def __unregister(self, dp): > + if dp.id in self.dps: > + del self.dps[dp.id] > + del self.port_state[dp.id] > + > + def __get_switch(self, dp): > + switch = Switch(dp) > + for ofpport in self.port_state[dp.id].itervalues(): > + switch.add_port(ofpport) > + return switch > + > + @handler.set_ev_cls(ofp_event.EventOFPStateChange, > + [handler.MAIN_DISPATCHER, handler.DEAD_DISPATCHER]) > + def state_change_handler(self, ev): > + dp = ev.datapath > + assert dp is not None > + LOG.debug(dp) > + > + if ev.state == handler.MAIN_DISPATCHER: > + self.__register(dp) > + switch = self.__get_switch(dp) > + LOG.debug('register %s', switch) > + self.send_event_to_observers(EventSwitchEnter(switch)) > + > + elif ev.state == handler.DEAD_DISPATCHER: > + # dp.id is None when datapath dies before handshake > + if dp.id is None: > + return > + switch = self.__get_switch(dp) > + self.__unregister(dp) > + LOG.debug('unregister %s', switch) > + self.send_event_to_observers(EventSwitchLeave(switch)) > + > + @handler.set_ev_cls(ofp_event.EventOFPPortStatus, > handler.MAIN_DISPATCHER) > + def port_status_handler(self, ev): > + msg = ev.msg > + reason = msg.reason > + dp = msg.datapath > + ofpport = msg.desc > + > + if reason == dp.ofproto.OFPPR_ADD: > + #LOG.debug('A port was added.' + > + # '(datapath id = %s, port number = %s)', > + # dp.id, ofpport.port_no) > + self.port_state[dp.id].add(ofpport.port_no, ofpport) > + self.send_event_to_observers( > + EventPortAdd(Port(dp.id, dp.ofproto, ofpport))) > + > + elif reason == dp.ofproto.OFPPR_DELETE: > + #LOG.debug('A port was deleted.' + > + # '(datapath id = %s, port number = %s)', > + # dp.id, ofpport.port_no) > + self.port_state[dp.id].remove(ofpport.port_no) > + self.send_event_to_observers( > + EventPortDelete(Port(dp.id, dp.ofproto, ofpport))) > + > + else: > + assert reason == dp.ofproto.OFPPR_MODIFY > + #LOG.debug('A port was modified.' + > + # '(datapath id = %s, port number = %s)', > + # dp.id, ofpport.port_no) > + self.port_state[dp.id].modify(ofpport.port_no, ofpport) > + self.send_event_to_observers( > + EventPortModify(Port(dp.id, dp.ofproto, ofpport))) > + > + @handler.set_ev_cls(EventSwitchListRequest) > + def request_handler(self, ev): > + #LOG.debug(ev) > + dpid = ev.dpid > + > + switches = [] > + if dpid is None: > + # reply all list > + for dp in self.dps.itervalues(): > + switches.append(self.__get_switch(dp)) > + elif dpid in self.dps: > + switches.append(self.__get_switch(self.dps[dpid])) > + > + self.send_reply(ev, EventSwitchListReply(switches)) > -- > 1.7.1 > > > > ------------------------------------------------------------------------------ > Everyone hates slow websites. So do we. > Make your web apps faster with AppDynamics > Download AppDynamics Lite for free today: > http://p.sf.net/sfu/appdyn_d2d_feb > _______________________________________________ > Ryu-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/ryu-devel > -- yamahata ------------------------------------------------------------------------------ Everyone hates slow websites. So do we. Make your web apps faster with AppDynamics Download AppDynamics Lite for free today: http://p.sf.net/sfu/appdyn_d2d_feb _______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
