This enables you to use Ryu BGP feature as 'bgp speaker' python
library, that is, without ryu-manager, RPC API, REST API, or other Ryu
stuff, you can use Ryu BGP feature in your python application (just
import bgpspeaker.py). The sample code and the API reference docs are
included too.

Signed-off-by: FUJITA Tomonori <[email protected]>
---
 doc/source/library.rst                       |   2 +
 doc/source/library_bgp_speaker.rst           |  44 ++++++
 doc/source/library_bgp_speaker_ref.rst       |  12 ++
 ryu/services/protocols/bgp/application.py    |  10 +-
 ryu/services/protocols/bgp/bgpspeaker.py     | 201 +++++++++++++++++++++++++++
 ryu/services/protocols/bgp/info_base/ipv4.py |   2 +
 ryu/services/protocols/bgp/signals/emit.py   |   6 +
 7 files changed, 272 insertions(+), 5 deletions(-)
 create mode 100644 doc/source/library_bgp_speaker.rst
 create mode 100644 doc/source/library_bgp_speaker_ref.rst
 create mode 100644 ryu/services/protocols/bgp/bgpspeaker.py

diff --git a/doc/source/library.rst b/doc/source/library.rst
index eee6877..38cc387 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -10,3 +10,5 @@ Ryu provides some useful library for your network 
applications.
    library_packet.rst
    library_packet_ref.rst
    library_of_config.rst
+   library_bgp_speaker.rst
+   library_bgp_speaker_ref.rst
diff --git a/doc/source/library_bgp_speaker.rst 
b/doc/source/library_bgp_speaker.rst
new file mode 100644
index 0000000..1dad7b5
--- /dev/null
+++ b/doc/source/library_bgp_speaker.rst
@@ -0,0 +1,44 @@
+*******************
+BGP speaker library
+*******************
+
+Introduction
+============
+
+Ryu BGP speaker library helps you to enable your code to speak BGP
+protocol. The library supports ipv4, ipv4 vpn, and ipv6 vpn address
+families.
+
+Example
+=======
+
+The following simple code creates a BGP instance with AS number 64512
+and Router ID 10.0.0.1. It tries to establish a bgp session with a
+peer (its IP is 192.168.177.32 and the AS number is 64512). The
+instance advertizes some prefixes.
+
+.. code-block:: python
+
+    import eventlet
+    from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker
+        
+    def dump_remote_best_path_change(event):
+        print 'the best path changed:', event.remote_as, event.prefix,\
+            event.nexthop, event.is_withdraw
+
+    if __name__ == "__main__":
+        speaker = BGPSpeaker(as_number=64512, router_id='10.0.0.1',
+                             
best_path_change_handler=dump_remote_best_path_change)
+        
+        speaker.neighbor_add('192.168.177.32', 64513)
+    
+        count = 1
+        while True:
+            eventlet.sleep(30)
+            prefix = '10.20.' + str(count) + '.0/24'
+            print "add a new prefix", prefix
+            speaker.prefix_add(prefix)
+            count += 1
+            if count == 4:
+                speaker.shutdown()
+                break
diff --git a/doc/source/library_bgp_speaker_ref.rst 
b/doc/source/library_bgp_speaker_ref.rst
new file mode 100644
index 0000000..493f322
--- /dev/null
+++ b/doc/source/library_bgp_speaker_ref.rst
@@ -0,0 +1,12 @@
+*********************************
+BGP speaker library API Reference
+*********************************
+
+BGPSpeaker class
+================
+
+.. autoclass:: ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker
+   :members:
+
+.. autoclass:: ryu.services.protocols.bgp.bgpspeaker.EventPrefix
+   :members:
diff --git a/ryu/services/protocols/bgp/application.py 
b/ryu/services/protocols/bgp/application.py
index 163e75f..b803d36 100644
--- a/ryu/services/protocols/bgp/application.py
+++ b/ryu/services/protocols/bgp/application.py
@@ -67,12 +67,12 @@ class ApplicationException(BGPSException):
     pass
 
 
-class BGPSpeaker(RyuApp):
+class RyuBGPSpeaker(RyuApp):
     def __init__(self, *args, **kwargs):
-        self.bind_ip = BGPSpeaker.validate_rpc_ip(CONF.bind_ip)
-        self.bind_port = BGPSpeaker.validate_rpc_port(CONF.bind_port)
+        self.bind_ip = RyuBGPSpeaker.validate_rpc_ip(CONF.bind_ip)
+        self.bind_port = RyuBGPSpeaker.validate_rpc_port(CONF.bind_port)
         self.config_file = CONF.bgp_config_file
-        super(BGPSpeaker, self).__init__(*args, **kwargs)
+        super(RyuBGPSpeaker, self).__init__(*args, **kwargs)
 
     def start(self):
         # Only two main green threads are required for APGW bgp-agent.
@@ -98,7 +98,7 @@ class BGPSpeaker(RyuApp):
                       net_ctrl.NC_RPC_BIND_PORT: self.bind_port})
         LOG.debug('Started Network Controller')
 
-        super(BGPSpeaker, self).start()
+        super(RyuBGPSpeaker, self).start()
 
         return t
 
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py 
b/ryu/services/protocols/bgp/bgpspeaker.py
new file mode 100644
index 0000000..5772e1b
--- /dev/null
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
@@ -0,0 +1,201 @@
+# Copyright (C) 2014 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.
+"""This module offers a class to enable your code to speak BGP protocol.
+
+"""
+
+from ryu.lib import hub
+from ryu.services.protocols.bgp.core_manager import CORE_MANAGER
+from ryu.services.protocols.bgp.signals.emit import BgpSignalBus
+from ryu.services.protocols.bgp.api.base import call
+from ryu.services.protocols.bgp.api.base import PREFIX
+from ryu.services.protocols.bgp.rtconf.common import LOCAL_AS
+from ryu.services.protocols.bgp.rtconf.common import ROUTER_ID
+from ryu.services.protocols.bgp.rtconf.common import BGP_SERVER_PORT
+from ryu.services.protocols.bgp.rtconf.common import DEFAULT_BGP_SERVER_PORT
+from ryu.services.protocols.bgp.rtconf.common \
+    import DEFAULT_REFRESH_MAX_EOR_TIME
+from ryu.services.protocols.bgp.rtconf.common \
+    import DEFAULT_REFRESH_STALEPATH_TIME
+from ryu.services.protocols.bgp.rtconf.common \
+    import DEFAULT_BGP_CONN_RETRY_TIME
+from ryu.services.protocols.bgp.rtconf.common import DEFAULT_LABEL_RANGE
+from ryu.services.protocols.bgp.rtconf.common import REFRESH_MAX_EOR_TIME
+from ryu.services.protocols.bgp.rtconf.common import REFRESH_STALEPATH_TIME
+from ryu.services.protocols.bgp.rtconf.common import LABEL_RANGE
+from ryu.services.protocols.bgp.rtconf import neighbors
+from ryu.services.protocols.bgp.application import RyuBGPSpeaker
+
+
+class EventPrefix(object):
+    """
+    Used to pass an update on any best remote path to
+    best_path_change_handler.
+
+    ================ ======================================================
+    Attribute        Description
+    ================ ======================================================
+    remote_as        The AS number of a peer that caused this change
+    route_dist       None in the case of ipv4 or ipv6 family
+    prefix           A prefix was changed
+    nexthop          The nexthop of the changed prefix
+    is_withdraw      True if this prefix has gone otherwise False
+    ================ ======================================================
+
+    """
+
+    def __init__(self, remote_as, route_dist, prefix, nexthop, is_withdraw):
+        self.remote_as = remote_as
+        self.route_dist = route_dist
+        self.prefix = prefix
+        self.nexthop = nexthop
+        self.is_withdraw = is_withdraw
+
+
+class BGPSpeaker(object):
+    def __init__(self, as_number, router_id,
+                 bgp_server_port=DEFAULT_BGP_SERVER_PORT,
+                 refresh_stalepath_time=DEFAULT_REFRESH_STALEPATH_TIME,
+                 refresh_max_eor_time=DEFAULT_REFRESH_MAX_EOR_TIME,
+                 best_path_change_handler=None):
+        """Create a new BGPSpeaker object with as_number and router_id to
+        listen on bgp_server_port.
+
+        ``as_number`` specifies an Autonomous Number. It must be an integer
+        between 1 and 65535.
+
+        ``router_id`` specifies BGP router identifier. It must be the
+        string representation of an IPv4 address (e.g. 10.0.0.1).
+
+        ``bgp_server_port`` specifies TCP listen port number. 179 is
+        used if not specified.
+
+        ``refresh_stalepath_time`` causes the BGP speaker to remove
+        stale routes from the BGP table after the timer expires, even
+        if the speaker does not receive a Router-Refresh End-of-RIB
+        message. This feature is disabled (not implemented yet).
+
+        ``refresh_max_eor_time`` causes the BGP speaker to generate a
+        Route-Refresh End-of-RIB message if it was not able to
+        generate one due to route flapping. This feature is disabled
+        (not implemented yet).
+
+        ``best_path_change_handler``, if specified, is called when any
+        best remote path is changed due to an update message or remote
+        peer down. The handler is supposed to take one argument, the
+        instance of an EventPrefix class instance.
+
+        """
+        super(BGPSpeaker, self).__init__()
+        self.speaker = RyuBGPSpeaker()
+
+        settings = {}
+        settings[LOCAL_AS] = as_number
+        settings[ROUTER_ID] = router_id
+        settings[BGP_SERVER_PORT] = bgp_server_port
+        settings[REFRESH_STALEPATH_TIME] = refresh_stalepath_time
+        settings[REFRESH_MAX_EOR_TIME] = refresh_max_eor_time
+        self._core_start(settings)
+        self._init_signal_listeners()
+        self._best_path_change_handler = best_path_change_handler
+
+    def _notify_best_path_changed(self, path):
+        if not path.source:
+            # ours
+            return
+        ev = EventPrefix(remote_as=path.source.remote_as,
+                         route_dist=None,
+                         prefix=path.nlri.addr + '/' + str(path.nlri.length),
+                         nexthop=path.nexthop, is_withdraw=path.is_withdraw)
+        if self._best_path_change_handler:
+            self._best_path_change_handler(ev)
+
+    def _init_signal_listeners(self):
+        CORE_MANAGER.get_core_service()._signal_bus.register_listener(
+            BgpSignalBus.BGP_BEST_PATH_CHANGED,
+            lambda _, dest: self._notify_best_path_changed(dest)
+        )
+
+    def _core_start(self, settings):
+        waiter = hub.Event()
+        call('core.start', waiter=waiter, **settings)
+        waiter.wait()
+
+    def _serve_forever(self):
+        pass
+
+    def shutdown(self):
+        """ Shutdown BGP speaker
+
+        """
+        call('core.stop')
+
+    def neighbor_add(self, address, remote_as):
+        """ This method registers a new neighbor. The BGP speaker tries to
+        establish a bgp session with the peer (accepts a connection
+        from the peer and also tries to connect to it).
+
+        ``address`` specifies the IP address of the peer. It must be
+        the string representation of an IP address. Only IP v4 is
+        supported now.
+
+        ``remote_as`` specifies the AS number of the peer. It must be
+        an integer between 1 and 65535.
+
+        """
+        bgp_neighbor = {}
+        bgp_neighbor[neighbors.IP_ADDRESS] = address
+        bgp_neighbor[neighbors.REMOTE_AS] = remote_as
+        call('neighbor.create', **bgp_neighbor)
+
+    def neighbor_del(self, address):
+        """ This method unregister the registered neighbor. If a session with
+        the peer exists, the session will be closed.
+
+        ``address`` specifies the IP address of the peer. It must be
+        the string representation of an IP address.
+
+        """
+        bgp_neighbor = {}
+        bgp_neighbor[neighbors.IP_ADDRESS] = address
+        call('neighbor.delete', **bgp_neighbor)
+
+    def prefix_add(self, prefix):
+        """ This method adds a new prefix to be advertized.
+
+        ``prefix`` must be the string representation of an IP network
+        (e.g., 10.1.1.0/24). Only IP v4 is supported now.
+
+        """
+        networks = {}
+        networks[PREFIX] = prefix
+        call('network.add', **networks)
+
+    def prefix_del(self):
+        """ Not implemented yet.
+
+        """
+        pass
+
+    def rib_get(self, family='ipv4'):
+        """ This method returns the BGP routing information in a json
+        format. This will be improved soon.
+
+        ``family`` specifies the address family of the RIB.
+
+        """
+        show = {}
+        show['params'] = ['rib', family]
+        return call('operator.show', **show)
diff --git a/ryu/services/protocols/bgp/info_base/ipv4.py 
b/ryu/services/protocols/bgp/info_base/ipv4.py
index f61bf7c..0839377 100644
--- a/ryu/services/protocols/bgp/info_base/ipv4.py
+++ b/ryu/services/protocols/bgp/info_base/ipv4.py
@@ -27,9 +27,11 @@ class IPv4Dest(Destination, NonVrfPathProcessingMixin):
 
     def _best_path_lost(self):
         NonVrfPathProcessingMixin._best_path_lost(self)
+        self._core_service._signal_bus.best_path_changed(best_path)
 
     def _new_best_path(self, best_path):
         NonVrfPathProcessingMixin._new_best_path(self, best_path)
+        self._core_service._signal_bus.best_path_changed(best_path)
 
 
 class Ipv4Table(Table):
diff --git a/ryu/services/protocols/bgp/signals/emit.py 
b/ryu/services/protocols/bgp/signals/emit.py
index 7f41c93..18a1287 100644
--- a/ryu/services/protocols/bgp/signals/emit.py
+++ b/ryu/services/protocols/bgp/signals/emit.py
@@ -11,6 +11,7 @@ class BgpSignalBus(SignalBus):
     BGP_VRF_STATS_CONFIG_CHANGED = (
         'core', 'vrf', 'config', 'stats', 'changed'
     )
+    BGP_BEST_PATH_CHANGED = ('core', 'best', 'changed')
 
     def bgp_error(self, peer, code, subcode, reason):
         return self.emit_signal(
@@ -53,3 +54,8 @@ class BgpSignalBus(SignalBus):
             self.BGP_VRF_STATS_CONFIG_CHANGED,
             vrf_conf
         )
+
+    def best_path_changed(self, best_path):
+        return self.emit_signal(
+            self.BGP_BEST_PATH_CHANGED,
+            best_path)
-- 
1.8.5.2 (Apple Git-48)


------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and their 
applications. Written by three acclaimed leaders in the field, 
this first edition is now available. Download your free book today!
http://p.sf.net/sfu/NeoTech
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to