Taku Fukushima | 24 Jul 13:07 2014

router_id in BGPSpeaker

Hi Ryu developers,

We're currently working on implementing the dynamic routing for external networks with BGP targeting OpenStack Juno. Please refer the following specs and a blueprint for more details.


We're thinking about to use Ryu's BGP libraries for the implementation. I started looking at the code and a question came to my mind after several code walkings.

BGPSpeaker requires router_id, a string representation of an IPv4 address, in it's __init__ but I couldn't find where the router_id was used. So I'd like to ask why BGPSpeaker takes the router_id as an argument of its initialiser. Is it actually used anywhere and am I missing anything? Otherwise, are you planning to use it in the future?

I list my walking paths below to make it clear how I thought the router_id was not used:


/Users/tfukushima/py/ryu/ryu% grep -rI "router_id(" . 
./services/protocols/bgp/core.py:    def router_id(self):
./services/protocols/bgp/processor.py:        best_path = _cmp_by_router_id(local_asn, path1, path2)
./services/protocols/bgp/processor.py:def _cmp_by_router_id(local_asn, path1, path2):
./services/protocols/bgp/processor.py:    def get_router_id(path_source, local_bgp_id):
./services/protocols/bgp/processor.py:    router_id1 = get_router_id(path_source1, local_bgp_id)
./services/protocols/bgp/processor.py:    router_id2 = get_router_id(path_source2, local_bgp_id)
./services/protocols/bgp/rtconf/common.py:def validate_router_id(router_id):
./services/protocols/bgp/rtconf/common.py:    def router_id(self):
/Users/tfukushima/py/ryu/ryu% grep -rI "router_id()" .
/Users/tfukushima/py/ryu/ryu%

Best regards,
Taku Fukushima


------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Ryu-devel mailing list
Ryu-devel@...
https://lists.sourceforge.net/lists/listinfo/ryu-devel
Zhonggen Sun | 24 Jul 12:53 2014

How to turn on debugging mode

Hi,

 

I want to turn on the debugging mode while executing the ryu application. Could you tell me how to turn on the debugging mode? Is there any tool to help debug codes step by step?

Thank you very much.

 

Best Regards,

Bruce



NOTE: The information in this email and any attachments may be confidential and/or legally privileged. This message may be read, copied and used only by the intended recipient. If you are not the intended recipient, please destroy this message, delete any copies held on your system and notify the sender immediately.

Toshiba Research Europe Limited, registered in England and Wales (2519556). Registered Office 208 Cambridge Science Park, Milton Road, Cambridge CB4 0GZ, England. Web: www.toshiba.eu/research/trl



This email has been scanned for email related threats and delivered safely by Mimecast.
For more information please visit http://www.mimecast.com
------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Ryu-devel mailing list
Ryu-devel@...
https://lists.sourceforge.net/lists/listinfo/ryu-devel
Hiroshi Yokoi | 23 Jul 10:39 2014
Picon

[PATCH 1/2] bgp: add med parameter to neighbor_add

Sorry, I changed parameter name for MED to uniform with add_vrf.
I resend patches for neighbor_add method and neighbor_update and
please ignore the patches that I sent before.

Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@...>
---
 ryu/services/protocols/bgp/bgpspeaker.py | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py
index b4a273c..67bd73c 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
 <at>  <at>  -47,6 +47,7  <at>  <at>  from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV4
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6
+from ryu.services.protocols.bgp.rtconf.base import MULTI_EXIT_DISC
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_IPV4
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV4
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV6
 <at>  <at>  -302,7 +303,7  <at>  <at>  class BGPSpeaker(object):
                      enable_ipv4=DEFAULT_CAP_MBGP_IPV4,
                      enable_vpnv4=DEFAULT_CAP_MBGP_VPNV4,
                      enable_vpnv6=DEFAULT_CAP_MBGP_VPNV6,
-                     next_hop=None, password=None):
+                     next_hop=None, password=None, multi_exit_disc=None):
         """ 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).
 <at>  <at>  -328,6 +329,11  <at>  <at>  class BGPSpeaker(object):

         ``password`` is used for the MD5 authentication if it's
         specified. By default, the MD5 authenticaiton is disabled.
+
+        ``multi_exit_disc`` specifies multi exit discriminator (MED) value.
+        The default is None and if not specified, MED value is
+        not sent to the neighbor. It must be an integer.
+
         """
         bgp_neighbor = {}
         bgp_neighbor[neighbors.IP_ADDRESS] = address
 <at>  <at>  -348,6 +354,10  <at>  <at>  class BGPSpeaker(object):
         else:
             # FIXME: should raise an exception
             pass
+
+        if multi_exit_disc:
+            bgp_neighbor[MULTI_EXIT_DISC] = multi_exit_disc
+
         call('neighbor.create', **bgp_neighbor)

     def neighbor_del(self, address):
--

-- 
1.8.5.2 (Apple Git-48)

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
马超 | 23 Jul 05:39 2014
Picon

some issues to writting ryu app

Hi,

   I installed ryu in openstack, and have defined packet_in_handler in my app, I want to check those packets and then let them go(datapath.send_msg(out)),    when I run app, some  errors came out:

connmgr|INFO|br-int<->tcp:10.0.0.201:6633: sending OFPBRC_BUFFER_EMPTY error reply to OFPT_PACKET_OUT message
pktbuf|WARN|attempt to reuse buffer 00000110

   I feel something should be done to avoid those packets sending before my checking, but I don't know how. 

   can you help me? thanks.

   if I send the mail too many times, please forgive me, the internet is not steady. 





------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Ryu-devel mailing list
Ryu-devel@...
https://lists.sourceforge.net/lists/listinfo/ryu-devel
Hiroshi Yokoi | 23 Jul 03:27 2014
Picon

[PATCH 1/2] bgp: add med parameter to neighbor_add

added parameter for Multi Exit Discriminator(MED) to the neighbor_add method.

Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@...>
---
 ryu/services/protocols/bgp/bgpspeaker.py | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py
index b4a273c..2fff03e 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
 <at>  <at>  -47,6 +47,7  <at>  <at>  from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV4
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4
 from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6
+from ryu.services.protocols.bgp.rtconf.base import MULTI_EXIT_DISC
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_IPV4
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV4
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV6
 <at>  <at>  -302,7 +303,7  <at>  <at>  class BGPSpeaker(object):
                      enable_ipv4=DEFAULT_CAP_MBGP_IPV4,
                      enable_vpnv4=DEFAULT_CAP_MBGP_VPNV4,
                      enable_vpnv6=DEFAULT_CAP_MBGP_VPNV6,
-                     next_hop=None, password=None):
+                     next_hop=None, password=None, med=None):
         """ 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).
 <at>  <at>  -328,6 +329,11  <at>  <at>  class BGPSpeaker(object):

         ``password`` is used for the MD5 authentication if it's
         specified. By default, the MD5 authenticaiton is disabled.
+
+        ``med`` specifies multi_exit discriminator (MED) value.
+        The default is None and if not specified, MED value is
+        not sent to the neighbor. It must be an integer.
+
         """
         bgp_neighbor = {}
         bgp_neighbor[neighbors.IP_ADDRESS] = address
 <at>  <at>  -348,6 +354,10  <at>  <at>  class BGPSpeaker(object):
         else:
             # FIXME: should raise an exception
             pass
+
+        if med:
+            bgp_neighbor[MULTI_EXIT_DISC] = med
+
         call('neighbor.create', **bgp_neighbor)

     def neighbor_del(self, address):
--

-- 
1.8.5.2 (Apple Git-48)

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
ISHIDA Wataru | 22 Jul 12:36 2014
Picon

[PATCH 7/7] bgp: add show neighbor filter command to ssh client


Signed-off-by: ISHIDA Wataru <ishida.wataru@...>
---
 .../bgp/operator/commands/show/neighbor.py         |   31 +++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

diff --git a/ryu/services/protocols/bgp/operator/commands/show/neighbor.py b/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
index 9f3f5ed..3b48f35 100644
--- a/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
+++ b/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
 <at>  <at>  -125,13 +125,42  <at>  <at>  class ReceivedRoutes(SentRoutes):
         return paths

+class Filter(Command):
+    help_msg = 'show neighbor filter information'
+    command = 'filter'
+    param_help_msg = '<ip_addr> <filter_family>{in, out, all}'
+
+    def action(self, params):
+        if len(params) != 2:
+            return WrongParamResp()
+
+        ip_addr, filter_family = params
+
+        if filter_family not in ['in', 'out', 'all']:
+            return WrongParamResp('wrong filter_family name')
+
+        core = self.api.get_core_service()
+        peer = core.peer_manager.get_by_addr(ip_addr)
+        if not peer:
+            return WrongParamResp('no peer found')
+
+        ret = {}
+        if filter_family != 'in':
+            ret['out'] = peer.out_filters
+        if filter_family != 'out':
+            ret['in'] = peer.in_filters
+
+        return CommandsResponse(STATUS_OK, ret)
+
+
 class Neighbor(Command):
     help_msg = 'show neighbor information'
     command = 'neighbor'
     subcommands = {
         'summary': NeighborSummary,
         'sent-routes': SentRoutes,
-        'received-routes': ReceivedRoutes
+        'received-routes': ReceivedRoutes,
+        'filter': Filter
     }

     fmtstr = ' {0:<12s} {1:<12s} {2:<}\n'
--

-- 
1.7.10.4

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
ISHIDA Wataru | 22 Jul 12:35 2014
Picon

[PATCH 6/7] bgp: manage filter in a peer instance instead of rtconf


rtconf is basically for static configuration and filter is
dynamic and also specific configuration for peer instance.

move filter things under peer instance, and change rtconf to do only
static configuration things from a configuration file

Signed-off-by: ISHIDA Wataru <ishida.wataru@...>
---
 ryu/services/protocols/bgp/api/rtconf.py       |   56 +++++---
 ryu/services/protocols/bgp/bgpspeaker.py       |   28 ++--
 ryu/services/protocols/bgp/peer.py             |  171 +++++++++++++-----------
 ryu/services/protocols/bgp/rtconf/neighbors.py |   39 +-----
 4 files changed, 150 insertions(+), 144 deletions(-)

diff --git a/ryu/services/protocols/bgp/api/rtconf.py b/ryu/services/protocols/bgp/api/rtconf.py
index 13d90f0..ccc4dea 100644
--- a/ryu/services/protocols/bgp/api/rtconf.py
+++ b/ryu/services/protocols/bgp/api/rtconf.py
 <at>  <at>  -78,12 +78,6  <at>  <at>  def update_neighbor(neigh_ip_address, changes):
         if k == neighbors.ENABLED:
             rets.append(update_neighbor_enabled(neigh_ip_address, v))

-        if k == neighbors.OUT_FILTER:
-            rets.append(_update_outfilter(neigh_ip_address, v))
-
-        if k == neighbors.IN_FILTER:
-            rets.append(_update_infilter(neigh_ip_address, v))
-
     return all(rets)

 <at>  <at>  -94,18 +88,6  <at>  <at>  def _update_med(neigh_ip_address, value):
     return True

-def _update_infilter(neigh_ip_address, value):
-    neigh_conf = _get_neighbor_conf(neigh_ip_address)
-    neigh_conf.in_filter = value
-    return True
-
-
-def _update_outfilter(neigh_ip_address, value):
-    neigh_conf = _get_neighbor_conf(neigh_ip_address)
-    neigh_conf.out_filter = value
-    return True
-
-
  <at> RegisterWithArgChecks(name='neighbor.delete',
                        req_args=[neighbors.IP_ADDRESS])
 def delete_neighbor(neigh_ip_address):
 <at>  <at>  -130,6 +112,44  <at>  <at>  def get_neighbors_conf():
     return CORE_MANAGER.neighbors_conf.settings

+ <at> RegisterWithArgChecks(name='neighbor.in_filter.get',
+                       req_args=[neighbors.IP_ADDRESS])
+def get_neighbor_in_filter(neigh_ip_address):
+    """Returns a neighbor in_filter for given ip address if exists."""
+    core = CORE_MANAGER.get_core_service()
+    peer = core.peer_manager.get_by_addr(neigh_ip_address)
+    return peer.in_filters
+
+
+ <at> RegisterWithArgChecks(name='neighbor.in_filter.set',
+                       req_args=[neighbors.IP_ADDRESS, neighbors.IN_FILTER])
+def set_neighbor_in_filter(neigh_ip_address, filters):
+    """Returns a neighbor in_filter for given ip address if exists."""
+    core = CORE_MANAGER.get_core_service()
+    peer = core.peer_manager.get_by_addr(neigh_ip_address)
+    peer.in_filters = filters
+    return True
+
+
+ <at> RegisterWithArgChecks(name='neighbor.out_filter.get',
+                       req_args=[neighbors.IP_ADDRESS])
+def get_neighbor_out_filter(neigh_ip_address):
+    """Returns a neighbor out_filter for given ip address if exists."""
+    core = CORE_MANAGER.get_core_service()
+    ret = core.peer_manager.get_by_addr(neigh_ip_address).out_filters
+    return ret
+
+
+ <at> RegisterWithArgChecks(name='neighbor.out_filter.set',
+                       req_args=[neighbors.IP_ADDRESS, neighbors.OUT_FILTER])
+def set_neighbor_in_filter(neigh_ip_address, filters):
+    """Returns a neighbor in_filter for given ip address if exists."""
+    core = CORE_MANAGER.get_core_service()
+    peer = core.peer_manager.get_by_addr(neigh_ip_address)
+    peer.out_filters = filters
+    return True
+
+
 # =============================================================================
 # VRF configuration related APIs
 # =============================================================================
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py
index 620a857..92c2c1b 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
 <at>  <at>  -366,14 +366,10  <at>  <at>  class BGPSpeaker(object):
         if prefix_lists is None:
             prefix_lists = []

-        func_name = 'neighbor.update'
-        prefix_value = {'prefix_lists': prefix_lists,
-                        'route_family': route_family}
-        filter_param = {neighbors.OUT_FILTER: prefix_value}
-
+        func_name = 'neighbor.out_filter.set'
         param = {}
         param[neighbors.IP_ADDRESS] = address
-        param[neighbors.CHANGES] = filter_param
+        param[neighbors.OUT_FILTER] = prefix_lists
         call(func_name, **param)

     def out_filter_get(self, address):
 <at>  <at>  -385,11 +381,11  <at>  <at>  class BGPSpeaker(object):

         """

-        func_name = 'neighbor.get'
+        func_name = 'neighbor.out_filter.get'
         param = {}
         param[neighbors.IP_ADDRESS] = address
-        settings = call(func_name, **param)
-        return settings[OUT_FILTER]
+        out_filter = call(func_name, **param)
+        return out_filter

     def in_filter_set(self, address, prefix_lists,
                       route_family=IN_FILTER_RF_IPv4_UC):
 <at>  <at>  -400,19 +396,15  <at>  <at>  class BGPSpeaker(object):
         if prefix_lists is None:
             prefix_lists = []

-        func_name = 'neighbor.update'
-        prefix_value = {'prefix_lists': prefix_lists,
-                        'route_family': route_family}
-        filter_param = {neighbors.IN_FILTER: prefix_value}
-
+        func_name = 'neighbor.in_filter.set'
         param = {}
         param[neighbors.IP_ADDRESS] = address
-        param[neighbors.CHANGES] = filter_param
+        param[neighbors.IN_FILTER] = prefix_lists
         call(func_name, **param)

     def in_filter_get(self, address):
-        func_name = 'neighbor.get'
+        func_name = 'neighbor.in_filter.get'
         param = {}
         param[neighbors.IP_ADDRESS] = address
-        settings = call(func_name, **param)
-        return settings[IN_FILTER]
+        in_filter = call(func_name, **param)
+        return in_filter
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 855101f..ec2b71b 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
 <at>  <at>  -332,6 +332,12  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
         # Adj-rib-out
         self._adj_rib_out = {}

+        # in-bound filters
+        self._in_filters = self._neigh_conf.in_filter
+
+        # out-bound filters
+        self._out_filters = self._neigh_conf.out_filter
+
      <at> property
     def remote_as(self):
         return self._neigh_conf.remote_as
 <at>  <at>  -364,6 +370,26  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
     def med(self):
         return self._neigh_conf.multi_exit_disc

+     <at> property
+    def in_filters(self):
+        return self._in_filters
+
+     <at> in_filters.setter
+    def in_filters(self, filters):
+        self._in_filters = [f.clone() for f in filters]
+        LOG.debug('set in-filter : %s' % filters)
+        self.on_update_in_filter()
+
+     <at> property
+    def out_filters(self):
+        return self._out_filters
+
+     <at> out_filters.setter
+    def out_filters(self, filters):
+        self._out_filters = [f.clone() for f in filters]
+        LOG.debug('set out-filter : %s' % filters)
+        self.on_update_out_filter()
+
     def is_mpbgp_cap_valid(self, route_family):
         if not self.in_established:
             raise ValueError('Invalid request: Peer not in established state')
 <at>  <at>  -449,47 +475,74  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
             for af in negotiated_afs:
                 self._fire_route_refresh(af)

-    def on_update_out_filter(self, conf_evt):
-        LOG.debug('on_update_out_filter fired')
-        event_value = conf_evt.value
-        prefix_lists = event_value['prefix_lists']
-        rf = event_value['route_family']
-
-        table = self._core_service.\
-            table_manager.get_global_table_by_route_family(rf)
-        for destination in table.itervalues():
-            LOG.debug('dest : %s' % destination)
-            sent_routes = destination.sent_routes_by_peer(self)
-            if len(sent_routes) == 0:
-                continue
+    def _apply_filter(self, filters, path):
+        block = False
+        blocked_cause = None

-            for sent_route in sent_routes:
-                path = sent_route.path
-                nlri_str = path.nlri.formatted_nlri_str
-                send_withdraw = False
-                for pl in prefix_lists:
-                    policy, result = pl.evaluate(path)
-
-                    if policy == PrefixList.POLICY_PERMIT and result:
-                        send_withdraw = False
-                        break
-                    elif policy == PrefixList.POLICY_DENY and result:
-                        send_withdraw = True
-                        break
-
-                outgoing_route = None
-                if send_withdraw:
-                    # send withdraw routes that have already been sent
-                    withdraw_clone = sent_route.path.clone(for_withdrawal=True)
-                    outgoing_route = OutgoingRoute(withdraw_clone)
-                    LOG.debug('send withdraw %s because of out filter'
-                              % nlri_str)
-                else:
-                    outgoing_route = OutgoingRoute(sent_route.path,
-                                                   for_route_refresh=True)
-                    LOG.debug('resend path : %s' % nlri_str)
+        for filter_ in filters:
+            policy, is_matched = filter_.evaluate(path)
+            if policy == PrefixList.POLICY_PERMIT and is_matched:
+                block = False
+                break
+            elif policy == PrefixList.POLICY_DENY and is_matched:
+                block = True
+                blocked_cause = filter_.prefix + ' - DENY'
+                break
+
+        return block, blocked_cause
+
+    def _apply_in_filter(self, path):
+        return self._apply_filter(self._in_filters, path)
+
+    def _apply_out_filter(self, path):
+        return self._apply_filter(self._out_filters, path)
+
+    def on_update_in_filter(self):
+        LOG.debug('on_update_in_filter fired')
+        for received_path in self._adj_rib_in.itervalues():
+            LOG.debug('received_path: %s' % received_path)
+            path = received_path.path
+            nlri_str = path.nlri.formatted_nlri_str
+            block, blocked_reason = self._apply_in_filter(path)
+            if block == received_path.filtered:
+                LOG.debug('block situation not changed: %s' % block)
+                continue
+            elif block:
+                # path wasn't blocked, but must be blocked by this update
+                path = sent_route.path.clone(for_withdrawal=True)
+                LOG.debug('withdraw %s because of in filter update'
+                          % nlri_str)
+            else:
+                # path was blocked, but mustn't be blocked by this update
+                LOG.debug('learn blocked %s because of in filter update'
+                          % nlri_str)
+            received_path.filtered = block
+            tm = self._core_service.table_manager
+            tm.learn_path(path)

-                self.enque_outgoing_msg(outgoing_route)
+    def on_update_out_filter(self):
+        LOG.debug('on_update_out_filter fired')
+        for sent_path in self._adj_rib_out.itervalues():
+            LOG.debug('sent_path: %s' % received_path)
+            path = sent_path.path
+            nlri_str = path.nlri.formatted_nlri_str
+            block, blocked_reason = self._apply_out_filter(path)
+            if block == sent_path.filtered:
+                LOG.debug('block situation not changed: %s' % block)
+                continue
+            elif block:
+                # path wasn't blocked, but must be blocked by this update
+                withdraw_clone = sent_route.path.clone(for_withdrawal=True)
+                outgoing_route = OutgoingRoute(withdraw_clone)
+                LOG.debug('send withdraw %s because of out filter update'
+                          % nlri_str)
+            else:
+                # path was blocked, but mustn't be blocked by this update
+                outgoing_route = OutgoingRoute(path)
+                LOG.debug('send blocked %s because of out filter update'
+                          % nlri_str)
+            sent_path.filtered = block
+            self.enque_outgoing_msg(outgoing_route)

     def __str__(self):
         return 'Peer(ip: %s, asn: %s)' % (self._neigh_conf.ip_address,
 <at>  <at>  -535,32 +588,17  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
         Populates Adj-RIB-out with corresponding `SentRoute`.
         """

-        # evaluate prefix list
-        rf = outgoing_route.path.route_family
-        allow_to_send = True
-        if rf in (RF_IPv4_UC, RF_IPv6_UC):
-            prefix_lists = self._neigh_conf.out_filter
-
-            if not outgoing_route.path.is_withdraw:
-                for prefix_list in prefix_lists:
-                    path = outgoing_route.path
-                    policy, is_matched = prefix_list.evaluate(path)
-                    if policy == PrefixList.POLICY_PERMIT and is_matched:
-                        allow_to_send = True
-                        break
-                    elif policy == PrefixList.POLICY_DENY and is_matched:
-                        allow_to_send = False
-                        blocked_cause = prefix_list.prefix + ' - DENY'
-                        break
+        path = outgoing_route.path
+        block, blocked_cause = self._apply_out_filter(path)

         nlri_str = outgoing_route.path.nlri.formatted_nlri_str
-        sent_route = SentRoute(outgoing_route.path, self, not allow_to_send)
+        sent_route = SentRoute(outgoing_route.path, self, block)
         self._adj_rib_out[nlri_str] = sent_route
         self._signal_bus.adj_rib_out_changed(self, sent_route)

         # TODO(PH): optimized by sending several prefixes per update.
         # Construct and send update message.
-        if allow_to_send:
+        if not block:
             update_msg = self._construct_update(outgoing_route)
             self._protocol.send(update_msg)
             # Collect update statistics.
 <at>  <at>  -1191,23 +1229,6  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
         if withdraw_list:
             self._extract_and_handle_bgp4_withdraws(withdraw_list)

-    def _apply_in_filter(self, path):
-        block = False
-        blocked_cause = None
-        prefix_lists = self._neigh_conf.in_filter
-
-        for prefix_list in prefix_lists:
-            policy, is_matched = prefix_list.evaluate(path)
-            if policy == PrefixList.POLICY_PERMIT and is_matched:
-                block = False
-                break
-            elif policy == PrefixList.POLICY_DENY and is_matched:
-                block = True
-                blocked_cause = prefix_list.prefix + ' - DENY'
-                break
-
-        return block, blocked_cause
-
     def _extract_and_handle_bgp4_new_paths(self, update_msg):
         """Extracts new paths advertised in the given update message's
          *MpReachNlri* attribute.
diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py
index 5b195ad..0d4ecf5 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
 <at>  <at>  -61,6 +61,7  <at>  <at>  from ryu.services.protocols.bgp.rtconf.base import validate_med
 from ryu.services.protocols.bgp.rtconf.base import validate_soo_list
 from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4
 from ryu.services.protocols.bgp.utils.validation import is_valid_old_asn
+from ryu.services.protocols.bgp.info_base.base import Filter
 from ryu.services.protocols.bgp.info_base.base import PrefixList

 LOG = logging.getLogger('bgpspeaker.rtconf.neighbor')
 <at>  <at>  -107,7 +108,7  <at>  <at>  def validate_enabled(enabled):
  <at> validate(name=CHANGES)
 def validate_changes(changes):
     for k, v in changes.iteritems():
-        if k not in (MULTI_EXIT_DISC, ENABLED, IN_FILTER, OUT_FILTER):
+        if k not in (MULTI_EXIT_DISC, ENABLED):
             raise ConfigValueError(desc="Unknown field to change: %s" % k)

         if k == MULTI_EXIT_DISC:
 <at>  <at>  -188,6 +189,9  <at>  <at>  SUPPORTED_FILTER_VALIDATORS = {

 def valid_filter(filter_):
+    if isinstance(filter_, Filter):
+        return filter_
+
     if not isinstance(filter_, dict):
         raise ConfigTypeError(desc='Invalid filter: %s' % filter_)

 <at>  <at>  -219,10 +223,8  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):

     UPDATE_ENABLED_EVT = 'update_enabled_evt'
     UPDATE_MED_EVT = 'update_med_evt'
-    UPDATE_OUT_FILTER_EVT = 'update_out_filter_evt'

-    VALID_EVT = frozenset([UPDATE_ENABLED_EVT, UPDATE_MED_EVT,
-                           UPDATE_OUT_FILTER_EVT])
+    VALID_EVT = frozenset([UPDATE_ENABLED_EVT, UPDATE_MED_EVT])
     REQUIRED_SETTINGS = frozenset([REMOTE_AS, IP_ADDRESS])
     OPTIONAL_SETTINGS = frozenset([CAP_REFRESH,
                                    CAP_ENHANCED_REFRESH,
 <at>  <at>  -433,33 +435,10  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
     def in_filter(self):
         return self._settings[IN_FILTER]

-     <at> in_filter.setter
-    def in_filter(self, value):
-        self._settings[IN_FILTER] = []
-        prefix_lists = value['prefix_lists']
-        for prefix_list in prefix_lists:
-            # copy PrefixList object and put it in the _settings
-            self._settings[IN_FILTER].append(prefix_list.clone())
-
-        LOG.debug('set in-filter : %s' % prefix_lists)
-
      <at> property
     def out_filter(self):
         return self._settings[OUT_FILTER]

-     <at> out_filter.setter
-    def out_filter(self, value):
-        self._settings[OUT_FILTER] = []
-        prefix_lists = value['prefix_lists']
-        for prefix_list in prefix_lists:
-            # copy PrefixList object and put it in the _settings
-            self._settings[OUT_FILTER].append(prefix_list.clone())
-
-        LOG.debug('set out-filter : %s' % prefix_lists)
-
-        # check sent_route
-        self._notify_listeners(NeighborConf.UPDATE_OUT_FILTER_EVT, value)
-
     def exceeds_max_prefix_allowed(self, prefix_count):
         allowed_max = self._settings[MAX_PREFIXES]
         does_exceed = False
 <at>  <at>  -603,8 +582,6  <at>  <at>  class NeighborConfListener(ConfWithIdListener, ConfWithStatsListener):
                                 self.on_update_enabled)
         neigh_conf.add_listener(NeighborConf.UPDATE_MED_EVT,
                                 self.on_update_med)
-        neigh_conf.add_listener(NeighborConf.UPDATE_OUT_FILTER_EVT,
-                                self.on_update_out_filter)

      <at> abstractmethod
     def on_update_enabled(self, evt):
 <at>  <at>  -613,10 +590,6  <at>  <at>  class NeighborConfListener(ConfWithIdListener, ConfWithStatsListener):
     def on_update_med(self, evt):
         raise NotImplementedError('This method should be overridden.')

-     <at> abstractmethod
-    def on_update_out_filter(self, evt):
-        raise NotImplementedError('This method should be overridden.')
-

 class NeighborsConfListener(BaseConfListener):
     """Base listener for change events to neighbor configuration container."""
--

-- 
1.7.10.4

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
ISHIDA Wataru | 22 Jul 12:35 2014
Picon

[PATCH 5/7] bgp: create adjacent rib in peer instance


this will be used to implement BMP(BGP monitering protocol) client

Signed-off-by: ISHIDA Wataru <ishida.wataru@...>
---
 ryu/services/protocols/bgp/model.py        |   35 +++++++++++++++++++++++++++-
 ryu/services/protocols/bgp/peer.py         |   34 ++++++++++++++++++++++++++-
 ryu/services/protocols/bgp/signals/emit.py |   12 ++++++++++
 3 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/ryu/services/protocols/bgp/model.py b/ryu/services/protocols/bgp/model.py
index 51c8bb0..86af6f4 100644
--- a/ryu/services/protocols/bgp/model.py
+++ b/ryu/services/protocols/bgp/model.py
 <at>  <at>  -19,6 +19,7  <at>  <at> 
  sessions.
 """
 import logging
+from time import localtime

 LOG = logging.getLogger('bgpspeaker.model')
 <at>  <at>  -130,7 +131,7  <at>  <at>  class SentRoute(object):
     about a particular BGP destination.
     """

-    def __init__(self, path, peer):
+    def __init__(self, path, peer, filtered=None, timestamp=None):
         assert(path and hasattr(peer, 'version_num'))

         self.path = path
 <at>  <at>  -138,6 +139,13  <at>  <at>  class SentRoute(object):
         # Peer to which this path was sent.
         self._sent_peer = peer

+        self.filtered = filtered
+
+        if timestamp:
+            self.timestamp = timestamp
+        else:
+            self.timestamp = localtime()
+
         # Automatically generated.
         #
         # self.next_sent_route
 <at>  <at>  -146,3 +154,28  <at>  <at>  class SentRoute(object):
      <at> property
     def sent_peer(self):
         return self._sent_peer
+
+
+class ReceivedRoute(object):
+    """Holds the information that has been received to one sinks
+    about a particular BGP destination.
+    """
+
+    def __init__(self, path, peer, filtered=None, timestamp=None):
+        assert(path and hasattr(peer, 'version_num'))
+
+        self.path = path
+
+        # Peer to which this path was received.
+        self._received_peer = peer
+
+        self.filtered = filtered
+
+        if timestamp:
+            self.timestamp = timestamp
+        else:
+            self.timestamp = localtime()
+
+     <at> property
+    def received_peer(self):
+        return self._received_peer
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 5685189..855101f 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
 <at>  <at>  -29,6 +29,7  <at>  <at>  from ryu.services.protocols.bgp.base import SUPPORTED_GLOBAL_RF
 from ryu.services.protocols.bgp import constants as const
 from ryu.services.protocols.bgp.model import OutgoingRoute
 from ryu.services.protocols.bgp.model import SentRoute
+from ryu.services.protocols.bgp.model import ReceivedRoute
 from ryu.services.protocols.bgp.info_base.base import PrefixList
 from ryu.services.protocols.bgp.net_ctrl import NET_CONTROLLER
 from ryu.services.protocols.bgp.rtconf.neighbors import NeighborConfListener
 <at>  <at>  -325,6 +326,12  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
         self._sent_init_non_rtc_update = False
         self._init_rtc_nlri_path = []

+        # Adj-rib-in
+        self._adj_rib_in = {}
+
+        # Adj-rib-out
+        self._adj_rib_out = {}
+
      <at> property
     def remote_as(self):
         return self._neigh_conf.remote_as
 <at>  <at>  -546,6 +553,11  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
                         blocked_cause = prefix_list.prefix + ' - DENY'
                         break

+        nlri_str = outgoing_route.path.nlri.formatted_nlri_str
+        sent_route = SentRoute(outgoing_route.path, self, not allow_to_send)
+        self._adj_rib_out[nlri_str] = sent_route
+        self._signal_bus.adj_rib_out_changed(self, sent_route)
+
         # TODO(PH): optimized by sending several prefixes per update.
         # Construct and send update message.
         if allow_to_send:
 <at>  <at>  -562,7 +574,6  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
         if (not outgoing_route.path.is_withdraw and
                 not outgoing_route.for_route_refresh):
             # Update the destination with new sent route.
-            sent_route = SentRoute(outgoing_route.path, self)
             tm = self._core_service.table_manager
             tm.remember_sent_route(sent_route)

 <at>  <at>  -1246,6 +1257,12  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
             LOG.debug('Extracted paths from Update msg.: %s' % new_path)

             block, blocked_cause = self._apply_in_filter(new_path)
+
+            nlri_str = new_path.nlri.formatted_nlri_str
+            received_route = ReceivedRoute(new_path, self, block)
+            self._adj_rib_in[nlri_str] = received_route
+            self._signal_bus.adj_rib_in_changed(self, received_route)
+
             if not block:
                 # Update appropriate table with new paths.
                 tm = self._core_service.table_manager
 <at>  <at>  -1301,6 +1318,11  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
             )

             block, blocked_cause = self._apply_in_filter(w_path)
+
+            received_route = ReceivedRoute(w_path, self, block)
+            self._adj_rib_in[nlri_str] = received_route
+            self._signal_bus.adj_rib_in_changed(self, received_route)
+
             if block:
                 # Update appropriate table with withdraws.
                 tm = self._core_service.table_manager
 <at>  <at>  -1387,6 +1409,11  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
             LOG.debug('Extracted paths from Update msg.: %s' % new_path)

             block, blocked_cause = self._apply_in_filter(new_path)
+
+            received_route = ReceivedRoute(new_path, self, block)
+            self._adj_rib_in[nlri_str] = received_route
+            self._signal_bus.adj_rib_in_changed(self, received_route)
+
             if block:
                 if msg_rf == RF_RTC_UC \
                         and self._init_rtc_nlri_path is not None:
 <at>  <at>  -1445,6 +1472,11  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
                 is_withdraw=True
             )
             block, blocked_cause = self._apply_in_filter(w_path)
+
+            received_route = ReceivedRoute(w_path, self, block)
+            self._adj_rib_in[nlri_str] = received_route
+            self._signal_bus.adj_rib_in_changed(self, received_route)
+
             if block:
                 # Update appropriate table with withdraws.
                 tm = self._core_service.table_manager
diff --git a/ryu/services/protocols/bgp/signals/emit.py b/ryu/services/protocols/bgp/signals/emit.py
index 890c1bc..f015fdb 100644
--- a/ryu/services/protocols/bgp/signals/emit.py
+++ b/ryu/services/protocols/bgp/signals/emit.py
 <at>  <at>  -12,6 +12,8  <at>  <at>  class BgpSignalBus(SignalBus):
         'core', 'vrf', 'config', 'stats', 'changed'
     )
     BGP_BEST_PATH_CHANGED = ('core', 'best', 'changed')
+    BGP_ADJ_RIB_IN_CHANGED = ('core', 'adj', 'rib', 'in', 'changed')
+    BGP_ADJ_RIB_OUT_CHANGED = ('core', 'adj', 'rib', 'out', 'changed')

     def bgp_error(self, peer, code, subcode, reason):
         return self.emit_signal(
 <at>  <at>  -59,3 +61,13  <at>  <at>  class BgpSignalBus(SignalBus):
         return self.emit_signal(
             self.BGP_BEST_PATH_CHANGED,
             {'path': path, 'is_withdraw': is_withdraw})
+
+    def adj_rib_in_changed(self, peer, received_route):
+        return self.emit_signal(
+            self.BGP_ADJ_RIB_IN_CHANGED,
+            {'peer': peer, 'received_route': received_route})
+
+    def adj_rib_out_changed(self, peer, sent_route):
+        return self.emit_signal(
+            self.BGP_ADJ_RIB_OUT_CHANGED,
+            {'peer': peer, 'sent_route': sent_route})
--

-- 
1.7.10.4

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
ISHIDA Wataru | 22 Jul 12:35 2014
Picon

[PATCH 4/7] bgp: add show neighbor command to ssh client


looks like,

bgpd> show neighbor
 IP Address   AS Number    BGP State
 10.0.0.1     64514        Established

Signed-off-by: ISHIDA Wataru <ishida.wataru@...>
---
 .../bgp/operator/commands/show/neighbor.py         |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/ryu/services/protocols/bgp/operator/commands/show/neighbor.py b/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
index bd3fda7..9f3f5ed 100644
--- a/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
+++ b/ryu/services/protocols/bgp/operator/commands/show/neighbor.py
 <at>  <at>  -133,3 +133,34  <at>  <at>  class Neighbor(Command):
         'sent-routes': SentRoutes,
         'received-routes': ReceivedRoutes
     }
+
+    fmtstr = ' {0:<12s} {1:<12s} {2:<}\n'
+
+    def action(self, params):
+        core_service = self.api.get_core_service()
+        core_service_view = CoreServiceDetailView(core_service)
+        peers_view = core_service_view.rel('peer_manager').rel('peers')
+
+        ret = peers_view.encode()
+        return CommandsResponse(STATUS_OK,
+                                [{'ip_addr': k,
+                                  'as_num': str(v['remote_as']),
+                                  'bgp_state': v['stats']['bgp_state']}
+                                 for k, v in ret.iteritems()])
+
+     <at> classmethod
+    def cli_resp_formatter(cls, resp):
+        if resp.status == STATUS_ERROR:
+            return Command.cli_resp_formatter(resp)
+        return cls._format_header() + cls._format_value(resp.value)
+
+     <at> classmethod
+    def _format_header(cls):
+        return cls.fmtstr.format('IP Address', 'AS Number', 'BGP State')
+
+     <at> classmethod
+    def _format_value(cls, value):
+        ret = ''
+        for v in value:
+            ret += cls.fmtstr.format(v['ip_addr'], v['as_num'], v['bgp_state'])
+        return ret
--

-- 
1.7.10.4

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
ISHIDA Wataru | 22 Jul 12:35 2014
Picon

[PATCH 3/7] bgp: add in-filter function


Signed-off-by: ISHIDA Wataru <ishida.wataru@...>
---
 ryu/services/protocols/bgp/api/rtconf.py       |    9 +++
 ryu/services/protocols/bgp/bgpspeaker.py       |   29 ++++++++++
 ryu/services/protocols/bgp/peer.py             |   70 +++++++++++++++++++-----
 ryu/services/protocols/bgp/rtconf/neighbors.py |   27 ++++++++-
 4 files changed, 118 insertions(+), 17 deletions(-)

diff --git a/ryu/services/protocols/bgp/api/rtconf.py b/ryu/services/protocols/bgp/api/rtconf.py
index 6ddc66e..13d90f0 100644
--- a/ryu/services/protocols/bgp/api/rtconf.py
+++ b/ryu/services/protocols/bgp/api/rtconf.py
 <at>  <at>  -81,6 +81,9  <at>  <at>  def update_neighbor(neigh_ip_address, changes):
         if k == neighbors.OUT_FILTER:
             rets.append(_update_outfilter(neigh_ip_address, v))

+        if k == neighbors.IN_FILTER:
+            rets.append(_update_infilter(neigh_ip_address, v))
+
     return all(rets)

 <at>  <at>  -91,6 +94,12  <at>  <at>  def _update_med(neigh_ip_address, value):
     return True

+def _update_infilter(neigh_ip_address, value):
+    neigh_conf = _get_neighbor_conf(neigh_ip_address)
+    neigh_conf.in_filter = value
+    return True
+
+
 def _update_outfilter(neigh_ip_address, value):
     neigh_conf = _get_neighbor_conf(neigh_ip_address)
     neigh_conf.out_filter = value
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py
index c482fd5..620a857 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
 <at>  <at>  -52,6 +52,7  <at>  <at>  from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV4
 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV6
 from ryu.services.protocols.bgp.rtconf.neighbors import PEER_NEXT_HOP
 from ryu.services.protocols.bgp.rtconf.neighbors import PASSWORD
+from ryu.services.protocols.bgp.rtconf.neighbors import IN_FILTER
 from ryu.services.protocols.bgp.rtconf.neighbors import OUT_FILTER
 from ryu.services.protocols.bgp.application import RyuBGPSpeaker
 from ryu.lib.packet.bgp import RF_IPv4_UC, RF_IPv6_UC
 <at>  <at>  -59,6 +60,8  <at>  <at>  from ryu.lib.packet.bgp import RF_IPv4_UC, RF_IPv6_UC

 OUT_FILTER_RF_IPv4_UC = RF_IPv4_UC
 OUT_FILTER_RF_IPv6_UC = RF_IPv6_UC
+IN_FILTER_RF_IPv4_UC = RF_IPv4_UC
+IN_FILTER_RF_IPv6_UC = RF_IPv6_UC

 class EventPrefix(object):
 <at>  <at>  -387,3 +390,29  <at>  <at>  class BGPSpeaker(object):
         param[neighbors.IP_ADDRESS] = address
         settings = call(func_name, **param)
         return settings[OUT_FILTER]
+
+    def in_filter_set(self, address, prefix_lists,
+                      route_family=IN_FILTER_RF_IPv4_UC):
+        assert route_family in (IN_FILTER_RF_IPv4_UC,
+                                IN_FILTER_RF_IPv6_UC),\
+            "route family must be IPv4 or IPv6"
+
+        if prefix_lists is None:
+            prefix_lists = []
+
+        func_name = 'neighbor.update'
+        prefix_value = {'prefix_lists': prefix_lists,
+                        'route_family': route_family}
+        filter_param = {neighbors.IN_FILTER: prefix_value}
+
+        param = {}
+        param[neighbors.IP_ADDRESS] = address
+        param[neighbors.CHANGES] = filter_param
+        call(func_name, **param)
+
+    def in_filter_get(self, address):
+        func_name = 'neighbor.get'
+        param = {}
+        param[neighbors.IP_ADDRESS] = address
+        settings = call(func_name, **param)
+        return settings[IN_FILTER]
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 95cfa6f..5685189 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
 <at>  <at>  -1180,6 +1180,23  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
         if withdraw_list:
             self._extract_and_handle_bgp4_withdraws(withdraw_list)

+    def _apply_in_filter(self, path):
+        block = False
+        blocked_cause = None
+        prefix_lists = self._neigh_conf.in_filter
+
+        for prefix_list in prefix_lists:
+            policy, is_matched = prefix_list.evaluate(path)
+            if policy == PrefixList.POLICY_PERMIT and is_matched:
+                block = False
+                break
+            elif policy == PrefixList.POLICY_DENY and is_matched:
+                block = True
+                blocked_cause = prefix_list.prefix + ' - DENY'
+                break
+
+        return block, blocked_cause
+
     def _extract_and_handle_bgp4_new_paths(self, update_msg):
         """Extracts new paths advertised in the given update message's
          *MpReachNlri* attribute.
 <at>  <at>  -1227,9 +1244,15  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
                 nexthop=next_hop
             )
             LOG.debug('Extracted paths from Update msg.: %s' % new_path)
-            # Update appropriate table with new paths.
-            tm = self._core_service.table_manager
-            tm.learn_path(new_path)
+
+            block, blocked_cause = self._apply_in_filter(new_path)
+            if not block:
+                # Update appropriate table with new paths.
+                tm = self._core_service.table_manager
+                tm.learn_path(new_path)
+            else:
+                LOG.debug('prefix : %s is blocked by in-bound filter : %s'
+                          % (msg_nlri, blocked_cause))

         # If update message had any qualifying new paths, do some book-keeping.
         if msg_nlri_list:
 <at>  <at>  -1276,9 +1299,15  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
                 w_nlri,
                 is_withdraw=True
             )
-            # Update appropriate table with withdraws.
-            tm = self._core_service.table_manager
-            tm.learn_path(w_path)
+
+            block, blocked_cause = self._apply_in_filter(w_path)
+            if block:
+                # Update appropriate table with withdraws.
+                tm = self._core_service.table_manager
+                tm.learn_path(w_path)
+            else:
+                LOG.debug('prefix : %s is blocked by in-bound filter : %s'
+                          % (msg_nlri, blocked_cause))

     def _extract_and_handle_mpbgp_new_paths(self, update_msg):
         """Extracts new paths advertised in the given update message's
 <at>  <at>  -1356,13 +1385,19  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
                 nexthop=next_hop
             )
             LOG.debug('Extracted paths from Update msg.: %s' % new_path)
-            if msg_rf == RF_RTC_UC \
-                    and self._init_rtc_nlri_path is not None:
-                self._init_rtc_nlri_path.append(new_path)
+
+            block, blocked_cause = self._apply_in_filter(new_path)
+            if block:
+                if msg_rf == RF_RTC_UC \
+                        and self._init_rtc_nlri_path is not None:
+                    self._init_rtc_nlri_path.append(new_path)
+                else:
+                    # Update appropriate table with new paths.
+                    tm = self._core_service.table_manager
+                    tm.learn_path(new_path)
             else:
-                # Update appropriate table with new paths.
-                tm = self._core_service.table_manager
-                tm.learn_path(new_path)
+                LOG.debug('prefix : %s is blocked by in-bound filter : %s'
+                          % (msg_nlri, blocked_cause))

         # If update message had any qualifying new paths, do some book-keeping.
         if msg_nlri_list:
 <at>  <at>  -1409,9 +1444,14  <at>  <at>  class Peer(Source, Sink, NeighborConfListener, Activity):
                 w_nlri,
                 is_withdraw=True
             )
-            # Update appropriate table with withdraws.
-            tm = self._core_service.table_manager
-            tm.learn_path(w_path)
+            block, blocked_cause = self._apply_in_filter(w_path)
+            if block:
+                # Update appropriate table with withdraws.
+                tm = self._core_service.table_manager
+                tm.learn_path(w_path)
+            else:
+                LOG.debug('prefix : %s is blocked by in-bound filter : %s'
+                          % (w_nlri, blocked_cause))

     def _handle_eor(self, route_family):
         """Currently we only handle EOR for RTC address-family.
diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py
index 39b58e3..5b195ad 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
 <at>  <at>  -74,6 +74,7  <at>  <at>  LOCAL_ADDRESS = 'local_address'
 LOCAL_PORT = 'local_port'
 PEER_NEXT_HOP = 'next_hop'
 PASSWORD = 'password'
+IN_FILTER = 'in_filter'
 OUT_FILTER = 'out_filter'

 # Default value constants.
 <at>  <at>  -87,6 +88,7  <at>  <at>  DEFAULT_CAP_MBGP_VPNV6 = False
 DEFAULT_HOLD_TIME = 40
 DEFAULT_ENABLED = True
 DEFAULT_CAP_RTC = False
+DEFAULT_IN_FILTER = []
 DEFAULT_OUT_FILTER = []

 # Default value for *MAX_PREFIXES* setting is set to 0.
 <at>  <at>  -105,7 +107,7  <at>  <at>  def validate_enabled(enabled):
  <at> validate(name=CHANGES)
 def validate_changes(changes):
     for k, v in changes.iteritems():
-        if k not in (MULTI_EXIT_DISC, ENABLED, OUT_FILTER):
+        if k not in (MULTI_EXIT_DISC, ENABLED, IN_FILTER, OUT_FILTER):
             raise ConfigValueError(desc="Unknown field to change: %s" % k)

         if k == MULTI_EXIT_DISC:
 <at>  <at>  -202,6 +204,11  <at>  <at>  def valid_filter(filter_):
     return SUPPORTED_FILTER_VALIDATORS[filter_['type']](filter_)

+ <at> validate(name=IN_FILTER)
+def validate_in_filters(filters):
+    return [valid_filter(filter_) for filter_ in filters]
+
+
  <at> validate(name=OUT_FILTER)
 def validate_out_filters(filters):
     return [valid_filter(filter_) for filter_ in filters]
 <at>  <at>  -226,7 +233,7  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
                                    ADVERTISE_PEER_AS, SITE_OF_ORIGINS,
                                    LOCAL_ADDRESS, LOCAL_PORT,
                                    PEER_NEXT_HOP, PASSWORD,
-                                   OUT_FILTER])
+                                   IN_FILTER, OUT_FILTER])

     def __init__(self, **kwargs):
         super(NeighborConf, self).__init__(**kwargs)
 <at>  <at>  -252,6 +259,8  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
             MAX_PREFIXES, DEFAULT_MAX_PREFIXES, **kwargs)
         self._settings[ADVERTISE_PEER_AS] = compute_optional_conf(
             ADVERTISE_PEER_AS, DEFAULT_ADVERTISE_PEER_AS, **kwargs)
+        self._settings[IN_FILTER] = compute_optional_conf(
+            IN_FILTER, DEFAULT_IN_FILTER, **kwargs)
         self._settings[OUT_FILTER] = compute_optional_conf(
             OUT_FILTER, DEFAULT_OUT_FILTER, **kwargs)

 <at>  <at>  -421,6 +430,20  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
         return self._settings[RTC_AS]

      <at> property
+    def in_filter(self):
+        return self._settings[IN_FILTER]
+
+     <at> in_filter.setter
+    def in_filter(self, value):
+        self._settings[IN_FILTER] = []
+        prefix_lists = value['prefix_lists']
+        for prefix_list in prefix_lists:
+            # copy PrefixList object and put it in the _settings
+            self._settings[IN_FILTER].append(prefix_list.clone())
+
+        LOG.debug('set in-filter : %s' % prefix_lists)
+
+     <at> property
     def out_filter(self):
         return self._settings[OUT_FILTER]

--

-- 
1.7.10.4

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
ISHIDA Wataru | 22 Jul 12:34 2014
Picon

[PATCH 2/7] bgp: enable filter configuration via configuration file


Signed-off-by: ISHIDA Wataru <ishida.wataru@...>
---
 ryu/services/protocols/bgp/rtconf/base.py      |    5 +--
 ryu/services/protocols/bgp/rtconf/neighbors.py |   51 +++++++++++++++++++++---
 2 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/ryu/services/protocols/bgp/rtconf/base.py b/ryu/services/protocols/bgp/rtconf/base.py
index e7578f8..8dc4665 100644
--- a/ryu/services/protocols/bgp/rtconf/base.py
+++ b/ryu/services/protocols/bgp/rtconf/base.py
 <at>  <at>  -63,9 +63,6  <at>  <at>  MULTI_EXIT_DISC = 'multi_exit_disc'
 # Extended community attribute route origin.
 SITE_OF_ORIGINS = 'site_of_origins'

-# OUT FILTER
-OUT_FILTER = 'out_filter'
-
 # Constants related to errors.
 CONF_NAME = 'conf_name'
 CONF_VALUE = 'conf_value'
 <at>  <at>  -714,7 +711,7  <at>  <at>  def compute_optional_conf(conf_name, default_value, **all_config):
     conf_value = all_config.get(conf_name)
     if conf_value is not None:
         # Validate configuration value.
-        get_validator(conf_name)(conf_value)
+        conf_value = get_validator(conf_name)(conf_value)
     else:
         conf_value = default_value
     return conf_value
diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py
index e41c078..39b58e3 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
 <at>  <at>  -59,9 +59,9  <at>  <at>  from ryu.services.protocols.bgp.rtconf.base import SITE_OF_ORIGINS
 from ryu.services.protocols.bgp.rtconf.base import validate
 from ryu.services.protocols.bgp.rtconf.base import validate_med
 from ryu.services.protocols.bgp.rtconf.base import validate_soo_list
-from ryu.services.protocols.bgp.rtconf.base import OUT_FILTER
 from ryu.services.protocols.bgp.utils.validation import is_valid_ipv4
 from ryu.services.protocols.bgp.utils.validation import is_valid_old_asn
+from ryu.services.protocols.bgp.info_base.base import PrefixList

 LOG = logging.getLogger('bgpspeaker.rtconf.neighbor')

 <at>  <at>  -87,6 +87,7  <at>  <at>  DEFAULT_CAP_MBGP_VPNV6 = False
 DEFAULT_HOLD_TIME = 40
 DEFAULT_ENABLED = True
 DEFAULT_CAP_RTC = False
+DEFAULT_OUT_FILTER = []

 # Default value for *MAX_PREFIXES* setting is set to 0.
 DEFAULT_MAX_PREFIXES = 0
 <at>  <at>  -166,6 +167,46  <at>  <at>  def validate_remote_as(asn):
     return asn

+def valid_prefix_filter(filter_):
+    policy = filter_.get('policy', None)
+    if policy == 'permit':
+        policy = PrefixList.POLICY_PERMIT
+    else:
+        policy = PrefixList.POLICY_DENY
+    prefix = filter_['prefix']
+    ge = filter_.get('ge', None)
+    le = filter_.get('le', None)
+    return PrefixList(prefix, policy, ge=ge, le=le)
+
+PREFIX_FILTER = 'prefix_filter'
+
+SUPPORTED_FILTER_VALIDATORS = {
+    PREFIX_FILTER: valid_prefix_filter
+}
+
+
+def valid_filter(filter_):
+    if not isinstance(filter_, dict):
+        raise ConfigTypeError(desc='Invalid filter: %s' % filter_)
+
+    if 'type' not in filter_:
+        raise ConfigTypeError(desc='Invalid filter: %s, needs \'type\' field'
+                              % filter_)
+
+    if not filter_['type'] in SUPPORTED_FILTER_VALIDATORS:
+        raise ConfigTypeError(desc='Invalid filter type: %s, supported filter'
+                              ' types are %s'
+                              % (filter_['type'],
+                                 SUPPORTED_FILTER_VALIDATORS.keys()))
+
+    return SUPPORTED_FILTER_VALIDATORS[filter_['type']](filter_)
+
+
+ <at> validate(name=OUT_FILTER)
+def validate_out_filters(filters):
+    return [valid_filter(filter_) for filter_ in filters]
+
+
 class NeighborConf(ConfWithId, ConfWithStats):
     """Class that encapsulates one neighbors' configuration."""

 <at>  <at>  -184,7 +225,8  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
                                    ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES,
                                    ADVERTISE_PEER_AS, SITE_OF_ORIGINS,
                                    LOCAL_ADDRESS, LOCAL_PORT,
-                                   PEER_NEXT_HOP, PASSWORD])
+                                   PEER_NEXT_HOP, PASSWORD,
+                                   OUT_FILTER])

     def __init__(self, **kwargs):
         super(NeighborConf, self).__init__(**kwargs)
 <at>  <at>  -210,6 +252,8  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
             MAX_PREFIXES, DEFAULT_MAX_PREFIXES, **kwargs)
         self._settings[ADVERTISE_PEER_AS] = compute_optional_conf(
             ADVERTISE_PEER_AS, DEFAULT_ADVERTISE_PEER_AS, **kwargs)
+        self._settings[OUT_FILTER] = compute_optional_conf(
+            OUT_FILTER, DEFAULT_OUT_FILTER, **kwargs)

         # We do not have valid default MED value.
         # If no MED attribute is provided then we do not have to use MED.
 <at>  <at>  -249,9 +293,6  <at>  <at>  class NeighborConf(ConfWithId, ConfWithStats):
         self._settings[RTC_AS] = \
             compute_optional_conf(RTC_AS, default_rt_as, **kwargs)

-        # out filter configuration
-        self._settings[OUT_FILTER] = []
-
         # Since ConfWithId' default values use str(self) and repr(self), we
         # call super method after we have initialized other settings.
         super(NeighborConf, self)._init_opt_settings(**kwargs)
--

-- 
1.7.10.4

------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds

Gmane