local preference supports IPv6 and VPNv4/v6 route family.

Signed-off-by: Hiroshi Yokoi <[email protected]>
---
 ryu/services/protocols/bgp/api/rtconf.py           | 44 +++++++++++++---
 ryu/services/protocols/bgp/bgpspeaker.py           | 28 +++++++++-
 ryu/services/protocols/bgp/constants.py            |  6 +++
 .../bgp/core_managers/configuration_manager.py     |  8 +++
 ryu/services/protocols/bgp/info_base/base.py       |  8 +--
 ryu/services/protocols/bgp/peer.py                 | 60 ++++++++++++++--------
 6 files changed, 120 insertions(+), 34 deletions(-)

diff --git a/ryu/services/protocols/bgp/api/rtconf.py 
b/ryu/services/protocols/bgp/api/rtconf.py
index ce98903..1d7e58e 100644
--- a/ryu/services/protocols/bgp/api/rtconf.py
+++ b/ryu/services/protocols/bgp/api/rtconf.py
@@ -29,6 +29,7 @@ from ryu.services.protocols.bgp.rtconf.vrfs import 
ROUTE_DISTINGUISHER
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF
 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
 from ryu.services.protocols.bgp.rtconf.vrfs import VrfConf
+from ryu.services.protocols.bgp import constants as const
 
 LOG = logging.getLogger('bgpspeaker.api.rtconf')
 
@@ -152,22 +153,49 @@ def set_neighbor_in_filter(neigh_ip_address, filters):
 
 @RegisterWithArgChecks(name='neighbor.attribute_map.set',
                        req_args=[neighbors.IP_ADDRESS,
-                                 neighbors.ATTRIBUTE_MAP])
-def set_neighbor_attribute_map(neigh_ip_address, attribute_maps):
-    """Returns a neighbor attribute_map for given ip address if exists."""
+                                 neighbors.ATTRIBUTE_MAP],
+                       opt_args=[ROUTE_DISTINGUISHER, VRF_RF])
+def set_neighbor_attribute_map(neigh_ip_address, at_maps,
+                               route_dist=None, route_family=VRF_RF_IPV4):
+    """set attribute_maps to the neighbor."""
     core = CORE_MANAGER.get_core_service()
     peer = core.peer_manager.get_by_addr(neigh_ip_address)
-    peer.attribute_maps = attribute_maps
+
+    at_maps_key = const.ATTR_MAPS_LABEL_DEFAULT
+    at_maps_dict = {}
+
+    if route_dist is not None:
+        vrf_conf = CORE_MANAGER.vrfs_conf.get_vrf_conf(route_dist, 
route_family)
+        if vrf_conf:
+            at_maps_key = ':'.join([route_dist, route_family])
+        else:
+            raise RuntimeConfigError(desc='No VrfConf with rd %s' %
+                                 route_dist)
+
+    at_maps_dict[const.ATTR_MAPS_LABEL_KEY] = at_maps_key
+    at_maps_dict[const.ATTR_MAPS_VALUE] = at_maps
+    peer.attribute_maps = at_maps_dict
+
     return True
 
 
 @RegisterWithArgChecks(name='neighbor.attribute_map.get',
-                       req_args=[neighbors.IP_ADDRESS])
-def get_neighbor_attribute_map(neigh_ip_address):
+                       req_args=[neighbors.IP_ADDRESS],
+                       opt_args=[ROUTE_DISTINGUISHER, VRF_RF])
+def get_neighbor_attribute_map(neigh_ip_address,route_dist=None,
+                               route_family=VRF_RF_IPV4):
     """Returns a neighbor attribute_map for given ip address if exists."""
     core = CORE_MANAGER.get_core_service()
-    ret = core.peer_manager.get_by_addr(neigh_ip_address).attribute_maps
-    return ret
+    peer = core.peer_manager.get_by_addr(neigh_ip_address)
+    at_maps_key = const.ATTR_MAPS_LABEL_DEFAULT
+
+    if route_dist is not None:
+        at_maps_key = ':'.join([route_dist, route_family])
+    at_maps = peer.attribute_maps.get(at_maps_key)
+    if at_maps:
+        return at_maps.get(const.ATTR_MAPS_ORG_KEY)
+    else:
+        return []
 
 # =============================================================================
 # VRF configuration related APIs
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py 
b/ryu/services/protocols/bgp/bgpspeaker.py
index 9844e08..3ef59ea 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
@@ -526,7 +526,8 @@ class BGPSpeaker(object):
         param['port'] = port
         call(func_name, **param)
 
-    def attribute_map_set(self, address, attribute_maps):
+    def attribute_map_set(self, address, attribute_maps,
+                          route_dist=None, route_family=RF_VPN_V4):
         """This method sets attribute mapping to a neighbor.
         attribute mapping can be used when you want to apply
         attribute to BGPUpdate under specific conditions.
@@ -537,6 +538,12 @@ class BGPSpeaker(object):
         before paths are advertised. All the items in the list must
         be an instance of AttributeMap class
 
+        ``route_dist`` specifies route dist in which attribute_maps
+        are added.
+
+        ``route_family`` specifies route family of the VRF.
+        This parameter must be RF_VPN_V4 or RF_VPN_V6.
+
         We can set AttributeMap to a neighbor as follows;
 
           pref_filter = PrefixFilter('192.168.103.0/30',
@@ -549,24 +556,41 @@ class BGPSpeaker(object):
 
         """
 
+        assert route_family in (RF_VPN_V4, RF_VPN_V6),\
+            'route_family must be RF_VPN_V4 or RF_VPN_V6'
+
         func_name = 'neighbor.attribute_map.set'
         param = {}
         param[neighbors.IP_ADDRESS] = address
         param[neighbors.ATTRIBUTE_MAP] = attribute_maps
+        if route_dist is not None:
+            param[vrfs.ROUTE_DISTINGUISHER] = route_dist
+            param[vrfs.VRF_RF] = route_family
         call(func_name, **param)
 
-    def attribute_map_get(self, address):
+    def attribute_map_get(self, address, route_dist=None, 
route_family=RF_VPN_V4):
         """This method gets in-bound filters of the specified neighbor.
 
         ``address`` specifies the IP address of the neighbor.
 
+        ``route_dist`` specifies route distinguisher that has attribute_maps.
+
+        ``route_family`` specifies route family of the VRF.
+        This parameter must be RF_VPN_V4 or RF_VPN_V6.
+
         Returns a list object containing an instance of AttributeMap
 
         """
 
+        assert route_family in (RF_VPN_V4, RF_VPN_V6),\
+            'route_family must be RF_VPN_V4 or RF_VPN_V6'
+
         func_name = 'neighbor.attribute_map.get'
         param = {}
         param[neighbors.IP_ADDRESS] = address
+        if route_dist is not None:
+            param[vrfs.ROUTE_DISTINGUISHER] = route_dist
+            param[vrfs.VRF_RF] = route_family
         attribute_maps = call(func_name, **param)
         return attribute_maps
 
diff --git a/ryu/services/protocols/bgp/constants.py 
b/ryu/services/protocols/bgp/constants.py
index b1af9b0..31c88fc 100644
--- a/ryu/services/protocols/bgp/constants.py
+++ b/ryu/services/protocols/bgp/constants.py
@@ -48,3 +48,9 @@ VRF_TABLE = 'vrf_table'
 # RTC EOR timer default value
 # Time to wait for RTC-EOR, before we can send initial UPDATE as per RFC
 RTC_EOR_DEFAULT_TIME = 60
+
+# Constants for AttributeMaps
+ATTR_MAPS_ORG_KEY = '__orig'
+ATTR_MAPS_LABEL_KEY = 'at_maps_key'
+ATTR_MAPS_LABEL_DEFAULT = 'default'
+ATTR_MAPS_VALUE = 'at_maps'
\ No newline at end of file
diff --git a/ryu/services/protocols/bgp/core_managers/configuration_manager.py 
b/ryu/services/protocols/bgp/core_managers/configuration_manager.py
index ffac9bc..ff3dd3b 100644
--- a/ryu/services/protocols/bgp/core_managers/configuration_manager.py
+++ b/ryu/services/protocols/bgp/core_managers/configuration_manager.py
@@ -94,6 +94,14 @@ class ConfigurationManager(CommonConfListener, 
VrfsConfListener,
 
         self._signal_bus.vrf_removed(vrf_conf.route_dist)
 
+        # Remove AttributeMaps under the removed vrf
+        rd = vrf_conf.route_dist
+        rf = vrf_conf.route_family
+        peers = self._peer_manager.iterpeers
+        for peer in peers:
+            key = ':'.join([rd, rf])
+            peer.attribute_maps.pop(key, None)
+
     def on_add_vrf_conf(self, evt):
         """Event handler for new VrfConf.
 
diff --git a/ryu/services/protocols/bgp/info_base/base.py 
b/ryu/services/protocols/bgp/info_base/base.py
index 13f02ca..0e56bd0 100644
--- a/ryu/services/protocols/bgp/info_base/base.py
+++ b/ryu/services/protocols/bgp/info_base/base.py
@@ -947,14 +947,14 @@ class PrefixFilter(Filter):
         ge and le condition,
         this method returns True as the matching result.
 
-        ``prefix`` specifies the prefix. prefix must be string.
+        ``path`` specifies the path that has prefix.
 
         """
-        prefix = path.nlri
+        nlri = path.nlri
 
         result = False
-        length = prefix.length
-        net = netaddr.IPNetwork(prefix.formatted_nlri_str)
+        length = nlri.length
+        net = netaddr.IPNetwork(nlri.prefix)
 
         if net in self._network:
             if self._ge is None and self._le is None:
diff --git a/ryu/services/protocols/bgp/peer.py 
b/ryu/services/protocols/bgp/peer.py
index 1461852..2418386 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
@@ -37,6 +37,9 @@ from ryu.services.protocols.bgp.rtconf.neighbors import 
NeighborConfListener
 from ryu.services.protocols.bgp.signals.emit import BgpSignalBus
 from ryu.services.protocols.bgp.speaker import BgpProtocol
 from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path
+from ryu.services.protocols.bgp.info_base.vpnv4 import Vpnv4Path
+from ryu.services.protocols.bgp.info_base.vpnv6 import Vpnv6Path
+from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4, VRF_RF_IPV6
 from ryu.services.protocols.bgp.utils import bgp as bgp_utils
 from ryu.services.protocols.bgp.utils.evtlet import EventletIOFactory
 from ryu.services.protocols.bgp.utils import stats
@@ -415,15 +418,18 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
 
     @property
     def attribute_maps(self):
-        return self._attribute_maps['__orig']\
-            if '__orig' in self._attribute_maps else []
+        return self._attribute_maps
 
     @attribute_maps.setter
     def attribute_maps(self, attribute_maps):
         _attr_maps = {}
-        _attr_maps.setdefault('__orig', [])
+        _attr_maps.setdefault(const.ATTR_MAPS_ORG_KEY, [])
 
-        for a in attribute_maps:
+        # key is 'default' or rd_rf that represents RD and route_family
+        key = attribute_maps[const.ATTR_MAPS_LABEL_KEY]
+        at_maps = attribute_maps[const.ATTR_MAPS_VALUE]
+
+        for a in at_maps:
             cloned = a.clone()
             LOG.debug("AttributeMap attr_type: %s, attr_value: %s",
                       cloned.attr_type, cloned.attr_value)
@@ -431,9 +437,9 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
             attr_list.append(cloned)
 
             # preserve original order of attribute_maps
-            _attr_maps['__orig'].append(cloned)
+            _attr_maps[const.ATTR_MAPS_ORG_KEY].append(cloned)
 
-        self._attribute_maps = _attr_maps
+        self._attribute_maps[key] = _attr_maps
         self.on_update_attribute_maps()
 
     def is_mpbgp_cap_valid(self, route_family):
@@ -908,20 +914,19 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
                 # attribute_maps and set local-pref value.
                 # If the path doesn't match, we set default local-pref 100.
                 localpref_attr = BGPPathAttributeLocalPref(100)
-                # TODO handle VPNv4Path
-                if isinstance(path, Ipv4Path):
-                    if AttributeMap.ATTR_LOCAL_PREF in self._attribute_maps:
-                        maps = \
-                            self._attribute_maps[AttributeMap.ATTR_LOCAL_PREF]
-                        for m in maps:
-                            cause, result = m.evaluate(path)
-                            LOG.debug(
-                                "local_pref evaluation result:%s, cause:%s",
-                                result, cause)
-
-                            if result:
-                                localpref_attr = m.get_attribute()
-                                break
+                key = const.ATTR_MAPS_LABEL_DEFAULT
+
+                if isinstance(path, (Vpnv4Path, Vpnv6Path)):
+                    nlri = nlri_list[0]
+                    rf = VRF_RF_IPV4 if isinstance(path, Vpnv4Path)\
+                        else VRF_RF_IPV6
+                    key = ':'.join([nlri.route_dist, rf])
+
+                attr_type = AttributeMap.ATTR_LOCAL_PREF
+                at_maps = self._attribute_maps.get(key, {})
+                result = self._lookup_attribute_map(at_maps, attr_type, path)
+                if result:
+                    localpref_attr = result
 
             # COMMUNITY Attribute.
             community_attr = pathattr_map.get(BGP_ATTR_TYPE_COMMUNITIES)
@@ -1972,3 +1977,18 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
             if self._neigh_conf.enabled:
                 if not self._connect_retry_event.is_set():
                     self._connect_retry_event.set()
+
+    @staticmethod
+    def _lookup_attribute_map(attribute_map, attr_type, path):
+        result_attr = None
+        if attr_type in attribute_map:
+            maps = attribute_map[attr_type]
+            for m in maps:
+                cause, result = m.evaluate(path)
+                LOG.debug(
+                    "local_pref evaluation result:%s, cause:%s",
+                    result, cause)
+                if result:
+                    result_attr = m.get_attribute()
+                    break
+        return result_attr
\ No newline at end of file
-- 
1.8.5.2 (Apple Git-48)



------------------------------------------------------------------------------
Want excitement?
Manually upgrade your production database.
When you want reliability, choose Perforce
Perforce version control. Predictably reliable.
http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to