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

Reply via email to