Please ignore previous patch, because I forgot to check coding style with pep8, here is the new patch
Signed-off-by: Takeshi <[email protected]> --- ryu/topology/api.py | 9 +++++++ ryu/topology/event.py | 23 ++++++++++++++++ ryu/topology/switches.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/ryu/topology/api.py b/ryu/topology/api.py index 7485a8e..0a61c1b 100644 --- a/ryu/topology/api.py +++ b/ryu/topology/api.py @@ -35,4 +35,13 @@ def get_all_link(app): return get_link(app) +def get_host(app, dpid=None): + rep = app.send_request(event.EventHostRequest(dpid)) + return rep.hosts + + +def get_all_hosts(app): + return get_host(app) + + app_manager.require_app('ryu.topology.switches', api_style=True) diff --git a/ryu/topology/event.py b/ryu/topology/event.py index bd87ab0..ea9d8ce 100644 --- a/ryu/topology/event.py +++ b/ryu/topology/event.py @@ -126,3 +126,26 @@ class EventLinkReply(event.EventReplyBase): def __str__(self): return 'EventLinkReply<dst=%s, dpid=%s, links=%s>' % \ (self.dst, self.dpid, len(self.links)) + + +class EventHostRequest(event.EventRequestBase): + # If dpid is None, reply all list + def __init__(self, dpid=None): + super(EventHostRequest, self).__init__() + self.dst = 'switches' + self.dpid = dpid + + def __str__(self): + return 'EventHostRequest<dpid=%s>' % \ + (self.dpid) + + +class EventHostReply(event.EventReplyBase): + def __init__(self, dst, dpid, hosts): + super(EventHostReply, self).__init__(dst) + self.dpid = dpid + self.hosts = hosts + + def __str__(self): + return 'EventLinkReply<dpid=%s, hosts=%s>' % \ + (self.dpid, self.hosts) diff --git a/ryu/topology/switches.py b/ryu/topology/switches.py index 63335f2..3f69f7c 100644 --- a/ryu/topology/switches.py +++ b/ryu/topology/switches.py @@ -46,6 +46,8 @@ CONF = cfg.CONF CONF.register_cli_opts([ cfg.BoolOpt('observe-links', default=False, help='observe link discovery events.'), + cfg.BoolOpt('observe-hosts', default=False, + help='observe host discovery events.'), cfg.BoolOpt('install-lldp-flow', default=True, help='link discovery: explicitly install flow entry ' 'to send lldp packet to controller'), @@ -158,6 +160,33 @@ class Link(object): return 'Link: %s to %s' % (self.src, self.dst) +class Host(object): + # This is data class passed by EventHostXXXX + def __init__(self, dpid, port, mac): + super(Host, self).__init__() + self.dpid = dpid + self.port = port + self.mac = mac + + def to_dict(self): + d = {'dpid': self.dpid, + 'port': self.port, + 'mac': self.mac} + return d + + def __eq__(self, other): + return self.mac == other.mac + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.mac) + + def __str__(self): + return 'Host<Mac address=%s>' % (self.mac, ) + + class PortState(dict): # dict: int port_no -> OFPPort port # OFPPort is defined in ryu.ofproto.ofproto_v1_X_parser @@ -451,9 +480,12 @@ class Switches(app_manager.RyuApp): self.port_state = {} # datapath_id => ports self.ports = PortDataState() # Port class -> PortData class self.links = LinkState() # Link class -> timestamp + self.hosts = {} self.is_active = True self.link_discovery = self.CONF.observe_links + self.host_discovery = self.CONF.observe_hosts + if self.link_discovery: self.install_flow = self.CONF.install_lldp_flow self.explicit_drop = self.CONF.explicit_drop @@ -681,7 +713,7 @@ class Switches(app_manager.RyuApp): @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) def packet_in_handler(self, ev): - if not self.link_discovery: + if not self.link_discovery and not self.host_discovery: return msg = ev.msg @@ -689,7 +721,25 @@ class Switches(app_manager.RyuApp): src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) except LLDPPacket.LLDPUnknownFormat as e: # This handler can receive all the packtes which can be - # not-LLDP packet. Ignore it silently + # not-LLDP packet. + # Check if it's new host + if self.host_discovery: + dpid = msg.datapath.id + port = -1 + + if msg.datapath.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: + port = msg.in_port + elif msg.datapath.ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: + port = msg.match['in_port'] + + pkt = packet.Packet(msg.data) + eth = pkt.get_protocols(ethernet.ethernet)[0] + mac = eth.src + + if mac not in self.hosts and port != -1: + LOG.debug('Found host(mac=%s) from dpid=%d, port=%d', mac, dpid, port) + self.hosts[mac] = Host(dpid, port, mac) + return dst_dpid = msg.datapath.id @@ -862,3 +912,18 @@ class Switches(app_manager.RyuApp): links = [link for link in self.links if link.src.dpid == dpid] rep = event.EventLinkReply(req.src, dpid, links) self.reply_to_request(req, rep) + + @set_ev_cls(event.EventHostRequest) + def host_request_handler(self, req): + # LOG.debug(req) + dpid = req.dpid + hosts = [] + + if dpid is None: + hosts = [host for host in self.hosts.itervalues()] + + else: + hosts = [host for host in self.hosts.itervalues() if host.dpid == dpid] + + rep = event.EventHostReply(req.src, dpid, hosts) + self.reply_to_request(req, rep) -- 2.3.2 (Apple Git-55) 2015-06-11 15:06 GMT+08:00 Yi Tseng <[email protected]>: > Hi > > I add --observe-hosts option to ryu-manager > > Here is new patch > > Signed-off-by: Takeshi <[email protected]> > --- > ryu/topology/api.py | 7 +++++ > ryu/topology/event.py | 23 ++++++++++++++++ > ryu/topology/switches.py | 71 > ++++++++++++++++++++++++++++++++++++++++++++++-- > 3 files changed, 99 insertions(+), 2 deletions(-) > > > diff --git a/ryu/topology/api.py b/ryu/topology/api.py > index 7485a8e..aa8a09f 100644 > --- a/ryu/topology/api.py > +++ b/ryu/topology/api.py > @@ -34,5 +34,12 @@ def get_link(app, dpid=None): > def get_all_link(app): > return get_link(app) > > +def get_host(app, dpid=None): > + rep = app.send_request(event.EventHostRequest(dpid)) > + return rep.hosts > + > +def get_all_hosts(app): > + return get_host(app) > + > > app_manager.require_app('ryu.topology.switches', api_style=True) > diff --git a/ryu/topology/event.py b/ryu/topology/event.py > index bd87ab0..17fcf94 100644 > --- a/ryu/topology/event.py > +++ b/ryu/topology/event.py > @@ -126,3 +126,26 @@ class EventLinkReply(event.EventReplyBase): > def __str__(self): > return 'EventLinkReply<dst=%s, dpid=%s, links=%s>' % \ > (self.dst, self.dpid, len(self.links)) > + > + > + > +class EventHostRequest(event.EventRequestBase): > + # If dpid is None, reply all list > + def __init__(self, dpid=None): > + super(EventHostRequest, self).__init__() > + self.dst = 'switches' > + self.dpid = dpid > + > + def __str__(self): > + return 'EventHostRequest<dpid=%s>' % \ > + (self.dpid) > + > +class EventHostReply(event.EventReplyBase): > + def __init__(self, dst, dpid, hosts): > + super(EventHostReply, self).__init__(dst) > + self.dpid = dpid > + self.hosts = hosts > + > + def __str__(self): > + return 'EventLinkReply<dpid=%s, hosts=%s>' % \ > + (self.dpid, self.hosts) > diff --git a/ryu/topology/switches.py b/ryu/topology/switches.py > index 63335f2..1212c6c 100644 > --- a/ryu/topology/switches.py > +++ b/ryu/topology/switches.py > @@ -46,6 +46,8 @@ CONF = cfg.CONF > CONF.register_cli_opts([ > cfg.BoolOpt('observe-links', default=False, > help='observe link discovery events.'), > + cfg.BoolOpt('observe-hosts', default=False, > + help='observe host discovery events.'), > cfg.BoolOpt('install-lldp-flow', default=True, > help='link discovery: explicitly install flow entry ' > 'to send lldp packet to controller'), > @@ -157,6 +159,34 @@ class Link(object): > def __str__(self): > return 'Link: %s to %s' % (self.src, self.dst) > > +class Host(object): > + # This is data class passed by EventHostXXXX > + def __init__(self, dpid, port, mac): > + super(Host, self).__init__() > + self.dpid = dpid > + self.port = port > + self.mac = mac > + > + def to_dict(self): > + d = { > + 'dpid': self.dpid, > + 'port': self.port, > + 'mac': self.mac > + } > + return d > + > + def __eq__(self, other): > + return self.mac == other.mac > + > + def __ne__(self, other): > + return not self.__eq__(other) > + > + def __hash__(self): > + return hash(self.mac) > + > + def __str__(self): > + return 'Host<Mac address=%s>' % (self.mac, ) > + > > class PortState(dict): > # dict: int port_no -> OFPPort port > @@ -451,9 +481,12 @@ class Switches(app_manager.RyuApp): > self.port_state = {} # datapath_id => ports > self.ports = PortDataState() # Port class -> PortData class > self.links = LinkState() # Link class -> timestamp > + self.hosts = {} > self.is_active = True > > self.link_discovery = self.CONF.observe_links > + self.host_discovery = self.CONF.observe_hosts > + > if self.link_discovery: > self.install_flow = self.CONF.install_lldp_flow > self.explicit_drop = self.CONF.explicit_drop > @@ -681,7 +714,7 @@ class Switches(app_manager.RyuApp): > > @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) > def packet_in_handler(self, ev): > - if not self.link_discovery: > + if not self.link_discovery and not self.host_discovery: > return > > msg = ev.msg > @@ -689,7 +722,25 @@ class Switches(app_manager.RyuApp): > src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) > except LLDPPacket.LLDPUnknownFormat as e: > # This handler can receive all the packtes which can be > - # not-LLDP packet. Ignore it silently > + # not-LLDP packet. > + # Check if it's new host > + if self.host_discovery: > + dpid = msg.datapath.id > + port = -1 > + > + if msg.datapath.ofproto.OFP_VERSION == > ofproto_v1_0.OFP_VERSION: > + port = msg.in_port > + elif msg.datapath.ofproto.OFP_VERSION >= > ofproto_v1_2.OFP_VERSION: > + port = msg.match['in_port'] > + > + pkt = packet.Packet(msg.data) > + eth = pkt.get_protocols(ethernet.ethernet)[0] > + mac = eth.src > + > + if mac not in self.hosts and port != -1: > + LOG.debug('Found host(mac=%s) from dpid=%d, port=%d', > mac, dpid, port) > + self.hosts[mac] = Host(dpid, port, mac) > + > return > > dst_dpid = msg.datapath.id > @@ -862,3 +913,19 @@ class Switches(app_manager.RyuApp): > links = [link for link in self.links if link.src.dpid == dpid] > rep = event.EventLinkReply(req.src, dpid, links) > self.reply_to_request(req, rep) > + > + @set_ev_cls(event.EventHostRequest) > + def host_request_handler(self, req): > + # LOG.debug(req) > + dpid = req.dpid > + hosts = [] > + > + if dpid is None: > + hosts = [host for host in self.hosts.itervalues()] > + > + else: > + hosts = [host for host in self.hosts.itervalues() if > host.dpid == dpid] > + > + rep = event.EventHostReply(req.src, dpid, hosts) > + self.reply_to_request(req, rep) > + > -- > 2.3.2 (Apple Git-55) > > > > > 2015-06-11 13:29 GMT+08:00 Yi Tseng <[email protected]>: > >> Hi >> >> Sorry that I forgot to remove comment (# this type is used for key value >> of LinkState) in class Host (I copied class Link and modify it) >> >> Should I send a new patch ? >> >> >> >> 2015-06-11 13:08 GMT+08:00 Yi Tseng <[email protected]>: >> >>> Hi >>> >>> I didn't concern that host can be configured to send lldp packets. >>> >>> If a host can be configured to send lldp packet, there will be two >>> situations: >>> >>> 1. Host always send lldp packets : ryu can't discover that host. >>> >>> 2. Host not always send lldp packet, sometimes it send normal packet : >>> ryu can discover it. >>> >>> I think maybe I can add "--observe-hosts" option to ryu manager and send >>> a new patch? >>> >>> >>> >>> >>> 2015-06-11 12:33 GMT+08:00 IWAMOTO Toshihiro <[email protected]>: >>> >>>> At Thu, 11 Jun 2015 02:30:40 +0800, >>>> Yi Tseng wrote: >>>> > >>>> > Signed-off-by: Takeshi <[email protected]> >>>> > --- >>>> > ryu/topology/api.py | 7 +++++ >>>> > ryu/topology/event.py | 23 +++++++++++++++++ >>>> > ryu/topology/switches.py | 66 >>>> > +++++++++++++++++++++++++++++++++++++++++++++++- >>>> > 3 files changed, 95 insertions(+), 1 deletion(-) >>>> >>>> > diff --git a/ryu/topology/switches.py b/ryu/topology/switches.py >>>> > index 63335f2..ab7f9f6 100644 >>>> > --- a/ryu/topology/switches.py >>>> > +++ b/ryu/topology/switches.py >>>> > @@ -157,6 +157,35 @@ class Link(object): >>>> > def __str__(self): >>>> > return 'Link: %s to %s' % (self.src, self.dst) >>>> > >>>> > +class Host(object): >>>> > + # This is data class passed by EventHostXXXX >>>> > + def __init__(self, dpid, port, mac): >>>> > + super(Host, self).__init__() >>>> > + self.dpid = dpid >>>> > + self.port = port >>>> > + self.mac = mac >>>> > + >>>> > + def to_dict(self): >>>> > + d = { >>>> > + 'dpid': self.dpid, >>>> > + 'port': self.port, >>>> > + 'mac': self.mac >>>> > + } >>>> > + return d >>>> > + >>>> > + # this type is used for key value of LinkState >>>> >>>> Really? And why are you ignoring dpid and port in comparison >>>> operators? >>>> >>>> > + def __eq__(self, other): >>>> > + return self.mac == other.mac >>>> > + >>>> > + def __ne__(self, other): >>>> > + return not self.__eq__(other) >>>> > + >>>> > + def __hash__(self): >>>> > + return hash(self.mac) >>>> > + >>>> > + def __str__(self): >>>> > + return 'Host<Mac address=%s>' % (self.mac, ) >>>> > + >>>> > >>>> > class PortState(dict): >>>> > # dict: int port_no -> OFPPort port >>>> > @@ -451,6 +480,7 @@ class Switches(app_manager.RyuApp): >>>> > self.port_state = {} # datapath_id => ports >>>> > self.ports = PortDataState() # Port class -> PortData class >>>> > self.links = LinkState() # Link class -> timestamp >>>> > + self.hosts = {} >>>> > self.is_active = True >>>> > >>>> > self.link_discovery = self.CONF.observe_links >>>> > @@ -689,7 +719,25 @@ class Switches(app_manager.RyuApp): >>>> > src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data) >>>> > except LLDPPacket.LLDPUnknownFormat as e: >>>> > # This handler can receive all the packtes which can be >>>> > - # not-LLDP packet. Ignore it silently >>>> > + # not-LLDP packet. >>>> > + # Check if it's new host >>>> > + >>>> > + dpid = msg.datapath.id >>>> > + port = -1 >>>> > + >>>> > + if msg.datapath.ofproto.OFP_VERSION == >>>> > ofproto_v1_0.OFP_VERSION: >>>> > + port = msg.in_port >>>> > + elif msg.datapath.ofproto.OFP_VERSION >= >>>> > ofproto_v1_2.OFP_VERSION: >>>> > + port = msg.match['in_port'] >>>> > + >>>> > + pkt = packet.Packet(msg.data) >>>> > + eth = pkt.get_protocols(ethernet.ethernet)[0] >>>> > + mac = eth.src >>>> > + >>>> > + if mac not in self.hosts and port != -1: >>>> > + LOG.debug('Found host(mac=%s) from dpid=%d, >>>> port=%d', mac, >>>> > dpid, port) >>>> > + self.hosts[mac] = Host(dpid, port, mac) >>>> > + >>>> > return >>>> > >>>> > dst_dpid = msg.datapath.id >>>> >>>> -- >>>> IWAMOTO Toshihiro >>>> >>> >>> >>> >>> -- >>> Yi Tseng (a.k.a Takeshi) >>> Taiwan National Chiao Tung University >>> Department of Computer Science >>> W2CNLab >>> >> >> >> >> -- >> Yi Tseng (a.k.a Takeshi) >> Taiwan National Chiao Tung University >> Department of Computer Science >> W2CNLab >> > > > > -- > Yi Tseng (a.k.a Takeshi) > Taiwan National Chiao Tung University > Department of Computer Science > W2CNLab > -- Yi Tseng (a.k.a Takeshi) Taiwan National Chiao Tung University Department of Computer Science W2CNLab
------------------------------------------------------------------------------
_______________________________________________ Ryu-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/ryu-devel
