Signed-off-by: ISHIDA Wataru <ishida.wat...@lab.ntt.co.jp>
---
 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
@@ -81,6 +81,9 @@ 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)
 
 
@@ -91,6 +94,12 @@ 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
@@ -52,6 +52,7 @@ 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
@@ -59,6 +60,8 @@ 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):
@@ -387,3 +390,29 @@ 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
@@ -1180,6 +1180,23 @@ 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.
@@ -1227,9 +1244,15 @@ 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:
@@ -1276,9 +1299,15 @@ 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
@@ -1356,13 +1385,19 @@ 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:
@@ -1409,9 +1444,14 @@ 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
@@ -74,6 +74,7 @@ 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.
@@ -87,6 +88,7 @@ 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.
@@ -105,7 +107,7 @@ def validate_enabled(enabled):
 @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:
@@ -202,6 +204,11 @@ def valid_filter(filter_):
     return SUPPORTED_FILTER_VALIDATORS[filter_['type']](filter_)
 
 
+@validate(name=IN_FILTER)
+def validate_in_filters(filters):
+    return [valid_filter(filter_) for filter_ in filters]
+
+
 @validate(name=OUT_FILTER)
 def validate_out_filters(filters):
     return [valid_filter(filter_) for filter_ in filters]
@@ -226,7 +233,7 @@ 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)
@@ -252,6 +259,8 @@ 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)
 
@@ -421,6 +430,20 @@ class NeighborConf(ConfWithId, ConfWithStats):
         return self._settings[RTC_AS]
 
     @property
+    def in_filter(self):
+        return self._settings[IN_FILTER]
+
+    @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)
+
+    @property
     def out_filter(self):
         return self._settings[OUT_FILTER]
 
-- 
1.7.10.4


------------------------------------------------------------------------------
Infragistics Professional
Build stunning WinForms apps today!
Reboot your WinForms applications with our WinForms controls. 
Build a bridge from your legacy apps to the future.
http://pubads.g.doubleclick.net/gampad/clk?id=153845071&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to